XMlLport Error - Multiple root elements!

ECEC Member Posts: 56
Hi.

I've developed a .net app that reads xml sent from a navision xmlport. My problem is that I've created an Xmlport over the Customers table.
The table looks like this:
Customer (table)
No (field)
Name (field)
Address (field)

The xmlport maps the data correctly but when I try to parse the xml data in the .net app it throws an exception saying that the xml data contains several root elements. (only 1 is allowed in xml). Anyone know how to solve this?
I thought that the Xmlport would handle the creation of a well-structured
xml document.

/EC

Comments

  • zimiwingszimiwings Member Posts: 20
    add a root Tag (SourceType = Text) at the top, so you get a correct xml-structure:

    <root>
    <customer field1 field2 field3 />
    <customer field1 field2 field3 />
    </root>
    Daniel Zimmermann
  • ECEC Member Posts: 56
    I have tried that.
    e.g.:
    someText (txt)
    -Customer (table)
    --No. (field)
    --Name (field)
    --Address (field)

    But then the data isn't mapped to the xmlport.
  • zimiwingszimiwings Member Posts: 20
    Hmm, this works usually fine for me...

    Maybe if you filter the Customer Records when calling the XML Port helps:
    Customer.SETRANGE("No.");
    NewFile.CREATE(Filename);
    NewFile.CREATEOUTSTREAM(ExportStream);
    XMLPORT.EXPORT(_yourXMLPort,ExportStream,Customer);
    
    
    Daniel Zimmermann
  • DenSterDenSter Member Posts: 8,307
    An XML document with multiple root elements is not well formed. Make your XMLPort comply with a well formed XML document and you should be fine.
  • ECEC Member Posts: 56
    Hmm, it doesn't work.

    If I use my xmlport where the root is Customer it works perfectly when setting Customer.SETRANGE("No.", '10000')- that is ranging on 1 value. But when I set the range to '' it screws up.
    Also I tried changing the Xmlport, as you said, so that I would have a root element of type text (btw, how do I set this root element?) but this does not work either, even when setting Customer.SETRANGE("No.", '10000') it stills screws up.
  • ECEC Member Posts: 56
    DenSter:
    I am well aware of the xml syntax. But how do I create an XmlPort that comply to XML standards?

    My XmlPort looks like this:
    Customer (table)
    -No (field)
    -Name (field)
    -Address (field)

    I thought this was enough and that the XMLPort would handle the creation of the xml document in a well-structured fashion. Am I sadly mistaking?
  • DenSterDenSter Member Posts: 8,307
    I think your XMLPort is set up fine, except for one thing. XMLPorts do NOT know how to update existing records, they only know how to create new records. If you want to also update existing records, you need to make your table elements temporary, and in your OnPostXMLPort you loop through the temp table and create/update your records.

    What I did for an Item XMLPort is call my root element TempInboundItem (by the way, you can have different tag names and variable names, so be careful you keep them apart in your code) and import the XML document into the temp table. Because it's a temp table, everything is new, so everything gets imported. Then, in the OnPostXMLPort trigger I do something like this (the actual code does a lot more, but this is the basic idea):
    IF TempInboundItem.FIND THEN BEGIN
      REPEAT
        // locItem = local rec variable
        IF NOT locItem.GET(TempInboundItem."No.") THEN BEGIN
          locItem.TRANSFERFIELDS(TempInboundItem);
          locItem.INSERT;
        END ELSE BEGIN
          locItem.TRANSFERFIELDS(TempInboundItem);
          locItem.MODIFY;
        END;
      UNTIL TempInboundItem.NEXT = 0;
    END;
    
    You could also do IF NOT INSERT THEN MODIFY, but that is less efficient code, and this way you can expand on each scenario.
  • DenSterDenSter Member Posts: 8,307
    hm, just saw you are exporting, not importing :oops:

    Can I ask exactly how are you running the XMLPort? It should work just fine. If the elements you showed us are all of your elements, then you have one root element and your xml should be well formed.
  • ECEC Member Posts: 56
    Either we're not talking about the same thing or else I've misunderstood the concept of XMLPorts.

    I don't want to update existing records. All I'm interested in is to get a range of f.ex. Customers and export these to an XML file that I can use elsewhere.

    I thought that XMLPort could be used to export Navision data to an XML file in an easy way instead of having to write the XML tags by hand.
  • DenSterDenSter Member Posts: 8,307
    That is exactly what XMLPorts do, but you can't just run an XMLPort from the object designer like a report or a dataport. I am asking you how you are trying to use an XMLPort to see where it goes wrong. :)

    It's a bit like running a report from code, and you need to send in the right record. There's a trick to it that you need to know. Once you know the trick it's not too complicated.
  • ECEC Member Posts: 56
    I've tried the following- (You know how my Xmlport looks).

    I call a function with a parameter (No that indicates the customer."No.".
    This function contains the following:
    rCustomer.SETFILTER(rCustomer."No.", No);
    IF rCustomer.FIND('-') THEN
    BEGIN
      XMLPort.EXPORT(50000, outStr, rCustomer); 
       //50000 = my xmlport number, outStr = outStream//
    END;
    

    I've also tried:
    rCustomer.SETFILTER(rCustomer."No.", No);
    IF rCustomer.FIND('-') THEN
    BEGIN
      myCustXmlPort.SETTABLEVIEW(rCustomer);
      myCustXmlPort.SETDESTINATION(outStr);
      myCustXmlPort.EXPORT;
    END;
    

    None of the above works, when I filter on more than one customer (that is rCustomer.SETFILTER("No.", '') for example.
  • ECEC Member Posts: 56
    I've tried the following- (You know how my Xmlport looks).

    I call a function with a parameter (No that indicates the customer."No.".
    This function contains the following:
    rCustomer.SETFILTER(rCustomer."No.", No);
    IF rCustomer.FIND('-') THEN
    BEGIN
      XMLPort.EXPORT(50000, outStr, rCustomer); 
       //50000 = my xmlport number, outStr = outStream//
    END;
    

    I've also tried:
    rCustomer.SETFILTER(rCustomer."No.", No);
    IF rCustomer.FIND('-') THEN
    BEGIN
      myCustXmlPort.SETTABLEVIEW(rCustomer);
      myCustXmlPort.SETDESTINATION(outStr);
      myCustXmlPort.EXPORT;
    END;
    

    None of the above works, when I filter on more than one customer (that is rCustomer.SETFILTER("No.", '') for example.
  • zimiwingszimiwings Member Posts: 20
    Okay, I'll try to make a walkthrough:

    This is what tht XML-Port should look like (I did not change any Properties, root has identation 0, customer has identation 1 and the other fields have identation 2):
    TagName	TagType	SourceType	DataSource
    root	Element	Text	<root>
    customer	Element	Table	<Customer>(Customer)
    No	Attribute	Field	Customer::No.
    name	Attribute	Field	Customer::Name
    adress	Attribute	Field	Customer::Address
    
    

    If you want to export all the Customers, use:
    Customer.SETFILTER("No."); (you should not use a FIND afterwards).

    If this does not work, I can send you the objects.
    Daniel Zimmermann
  • ECEC Member Posts: 56
    I'm sorry- It's not working.

    I think it's the root element that's causing the problem. Because If I remove that it's works fine when filtering on f.example. rCustomer.SETFILTER("No.", '10000').
  • DenSterDenSter Member Posts: 8,307
    rCustomer.SETFILTER("No.", '') sets a filter on where No equals '', that does not clear the filter. If you want to clear the filter on the No field, you need to do rCustomer.SETFILTER("No.")
  • zimiwingszimiwings Member Posts: 20
    EC wrote:
    I think it's the root element that's causing the problem.
    No can't be, maybe have a look at XMLPort 5506, it also has a root Element first, that is of Text Type.
    Daniel Zimmermann
  • ECEC Member Posts: 56
    You're right. It's not that then. I just think it seems odd that with no root element it works perfectly (when filtering on f.ex. '10000').
    Anyhow don't you mean rCustomer.SETRANGE("No.") instead of rCustomer.SETFILTER("No.") ??

    It's not working either way. It's really beginning to bug me. I feel like I've tried everything.
  • DenSterDenSter Member Posts: 8,307
    The difference is that '10000' is a valid No field value, and '' is not. Open the Customer list, put your cursor on the No field and set a filter with value '' (actualy type in two single quotes, which is what you do when you do SETFILTER("No.",'')) and you'll see that the customer list goes empty. Both SETFILTER and SETRANGE should work without a parameter to clear the filter.

    I think if you have the Customer as the root element, then SETTABLEVIEW works, and if it's not the root element it doesn't work. The problem is though that if you use the Customer table as the root element, and you have more than one record, your XML is no longer well formed.

    You're probably going to have to write a function inside your XMLPort to send in a customer record variable to use for exporting. I would have to experiment myself to make this work, and unfortunately right now I don't have much time.
  • ECEC Member Posts: 56
    Hi.

    I just tried creating a test codeunit that creates a file, and streams the output from my xmlport to this file. It worked like a charm.
    So the error must be somewhere else in my code.

    Thanks for all the help and quick replies.

    /EC
  • DenSterDenSter Member Posts: 8,307
    Let us know if you find out what it was. I found this link with a movie that explains XMLPorts a little bit.
  • ECEC Member Posts: 56
    I think I've found the problem.

    The .Net app I've written and Navision communicates through MessageQueues.

    So the thing I've been dealing with today was that when I export an XMLPort to the outStream that I'm using an error occurs. I don't know which error, but if I do myXmlPort.Export to an outstream created by a file everything works like a charm. But that's not what I want.

    I want to export to the outStream that is being passed to the MessageQueue. (the outstream is initialized by
    outStream := outMessage.GetStream();
    

    The strange thing is that when I export another xmlport I have it works fine but then again that Xmlport isn't mapped to a table. It just has one tag which is BigText.

    Anyone can help with this or should I create a new topic?
  • DenSterDenSter Member Posts: 8,307
    That's probably a different topic :). Have you tried to load the outstream into a DOM Document object and send that to MSMQ?
  • ECEC Member Posts: 56
    I've tried that too. And it won't work. The error is that the upper element isn't correct. That is the root element.

    Even if I load the xml data from a file to a DOM object and then to the outstream it still don't work.

    I'm not all that happy about working with flat files, as the data is to be transferred to a webservice.
Sign In or Register to comment.