.Net SelectSingleNode() problems

Lars_WestmanLars_Westman Member Posts: 116
edited 2014-05-07 in NAV Three Tier
I have started the move from COM to .Net in a solution which involves sending a webservice request and receiving and getting data out of the response. The request and getting the XML data back into an variable of the type System.Xml.XmlDocument.System.Xml is no problem (lets call this variable for "XMLDoc" here). I can also use XMLDoc.GetElementsByTagName('NodeName') to navigate to a set of nodes to loop through. My problem starts when I want to get values from child nodes.

Example of XML:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <soap:Body>
  <ReqResponse xmlns="http://services.thedomain.info/the.appname.v3">
   <ReqResult>
    <Result>Saved</Result>
    <Number>6609403768</Number>
    <Id>0114</Id>
    <Details>
     <Detail>
      <Number>373400306320689675</Number>
     </Detail>
     <Detail>
      <Number>373400306320689859</Number>
     </Detail>
    </Details>
   </ReqResult>
  </ReqResponse>
 </soap:Body>
</soap:Envelope>

With COM i could do like this to get the value from the node called 'Result':
CurrNodeList := XMLDoc.getElementsByTagName(ResponseText);
CurrNode := CurrNodeList.item(0);
CurrNode2 := CurrNode.selectSingleNode('Result');
MESSAGE(CurrNode2.text);

This would give a message box saying "Saved" with the XML sample data above. But with .Net variables "SelectSingleNode" does not return anything. I think it has something to do with the namespace which suddenly seems to have become important. I just haven't figured how to deal with it yet so any help would be great. ](*,)

Another common thing I often do with the xml data is to loop through instances of nodes such as the "ReqResult" above. Then I use CurrNode := CurrNodeList.item(0..n) in a FOR loop and want to pick values from the child nodes. This is easy with COM but of course I get the same problem as in my example above.

Any hint in the right direction is appreciated :D

Edit: I got the solution for this in an email just after I posted this \:D/

The trick is to assign a NamspaceManager variable. The variable is of the type System.Xml.XmlNamespaceManager.System.Xml. Lets call it "NsMgr". When the XMLDoc is loaded these two lines of code is needed to assign NsMgr based on the XML example above:
NsMgr := NsMgr.XmlNamespaceManager(XMLDoc.NameTable);
NsMgr.AddNamespace('ns', 'http://services.thedomain.info/the.appname.v3');
And the node is found with:
CurrNode2 := CurrNode.SelectSingleNode('ns:Result');
//Lars

Answers

  • mdPartnerNLmdPartnerNL Member Posts: 802
    Thx, again a topic which should me moved to tips.

    You showed the code snippet with COM
    Could you show the full code snippet with .NET too?
  • Lars_WestmanLars_Westman Member Posts: 116
    ....Could you show the full code snippet with .NET too?

    It was already there in the post, but I have set code tags on it now.
  • jordi79jordi79 Member Posts: 273
    I am stuck. I did similar to what you are doing, but still could not get the SelectSingleNode to work. SelectSingleNode will work as long as there are no XMLNS definition in the file. But once there is xmlns definition, then it will not work.
    Name	DataType	Subtype	Length
    XMLDoc	DotNet	System.Xml.XmlDocument.'System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    Node	DotNet	System.Xml.XmlNode.'System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    Node2	DotNet	System.Xml.XmlNode.'System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    NameSpaceMgr	DotNet	System.Xml.XmlNamespaceManager.'System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    FileName	Text		250
    FileMgmt	Codeunit	File Management	
    f	File		
    FileInStream	InStream		
    
    CLEARALL();
    XMLDoc := XMLDoc.XmlDocument;     
    FileName := 'c:\temp\temp1.xml';
    FileName := FileMgmt.UploadFileSilent(FileName);
    IF NOT EXISTS(FileName) THEN EXIT;
    f.OPEN(FileName);
    f.TEXTMODE(TRUE);
    f.CREATEINSTREAM(FileInStream);
    XMLDoc.Load(FileInStream);
    Node := XMLDoc.DocumentElement;
    NameSpaceMgr := NameSpaceMgr.XmlNamespaceManager(XMLDoc.NameTable);
    NameSpaceMgr.AddNamespace('urn', 'oasis:names:specification:ubl:schema:xsd:Invoice-2');
    
    Node2 := Node.SelectSingleNode('invoice', NameSpaceMgr);
    MESSAGE(Node2.InnerText);  // error here
    

    The XML File:
    <content xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
    	<invoice>
    		<id>inv_001</id>
    		<name>user name</name>
    	</invoice>
    </content>
    
  • SiStSiSt Member Posts: 46
    You cannot select "invoic" directly, as it is part of the parent namespace. The correct way to select it is to use the namespace name followed by ':' and then the tag name.

    Like it is shown in the first post of this topic:
    CurrNode2 := CurrNode.SelectSingleNode('ns:Result');
    

    So, for your example, you will have to define the namespace manager as following:
    NameSpaceMgr.AddNamespace('ns', 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2');
    
    and select the node by using:
    Node2 := Node.SelectSingleNode('ns:invoice', NameSpaceMgr);
    
    I hope it will work, I haven't tested it.
  • jordi79jordi79 Member Posts: 273
    Yes. it works now. So, that means empty name spaces, have to be explicitly added into NameSpaceManager as "ns".
    Anyway my complete solution below:

    What it does is that it will auto add all name spaces.

    XML File:
    <content xmlns="dummyxyz" xmlns:abc="dummy123" xmlns:def="dummy456">
    	<invoice>
    		<id>inv_001</id>
    		<abc:name>user name</abc:name>
    		<def:name>user name</def:name>
    	</invoice>
    </content>
    

    Variables:
    Name	DataType	Subtype	Length
    XMLDoc	DotNet	System.Xml.XmlDocument.'System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    Node1	DotNet	System.Xml.XmlNode.'System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    Node2	DotNet	System.Xml.XmlNode.'System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    Node3	DotNet	System.Xml.XmlNode.'System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    NameSpaceMgr	DotNet	System.Xml.XmlNamespaceManager.'System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    XPathNavigator	DotNet	System.Xml.XPath.XPathNavigator.'System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    IDicEnum	DotNet	System.Collections.Generic.SortedDictionary`2+Enumerator.'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    IDic	DotNet	System.Collections.Generic.SortedDictionary`2.'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    IDicKeys	DotNet	System.Collections.Generic.SortedDictionary`2+KeyCollection.'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    IDicValues	DotNet	System.Collections.Generic.SortedDictionary`2+ValueCollection.'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    IDicKeysEnum	DotNet	System.Collections.Generic.SortedDictionary`2+KeyCollection+Enumerator.'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    IDicValuesEnum	DotNet	System.Collections.Generic.SortedDictionary`2+ValueCollection+Enumerator.'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    XMLNameSpaceScope	DotNet	System.Xml.XmlNamespaceScope.'System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    FileName	Text		250
    FileMgmt	Codeunit	File Management	
    f	File		
    FileInStream	InStream
    

    Code:
    CLEARALL();
    XMLDoc := XMLDoc.XmlDocument;     
    
    FileName := 'c:\temp\temp1.xml';
    FileName := FileMgmt.UploadFileSilent(FileName);
    IF NOT EXISTS(FileName) THEN EXIT;
    f.OPEN(FileName);
    f.TEXTMODE(TRUE);
    f.CREATEINSTREAM(FileInStream);
    XMLDoc.Load(FileInStream);
    Node1 := XMLDoc.DocumentElement;
    
    NameSpaceMgr := NameSpaceMgr.XmlNamespaceManager(XMLDoc.NameTable);
    XPathNavigator := Node1.CreateNavigator;
    IDic := XPathNavigator.GetNamespacesInScope(XMLNameSpaceScope.All);
    IDicKeys := IDic.Keys;
    IDicValues := IDic.Values;
    IDicKeysEnum := IDicKeys.GetEnumerator;
    IDicValuesEnum := IDicValues.GetEnumerator;
    
    WHILE IDicKeysEnum.MoveNext DO BEGIN
      IDicKeys := IDicKeysEnum.Current;
      IDicValuesEnum.MoveNext;
      IDicValues := IDicValuesEnum.Current;
      IF FORMAT(IDicKeys.ToString) <> '' THEN
        NameSpaceMgr.AddNamespace(IDicKeys.ToString, IDicValues.ToString)
      ELSE
        NameSpaceMgr.AddNamespace('ns', IDicValues.ToString);
    END;
    
    Node1 := XMLDoc.DocumentElement;
    MESSAGE(Node1.Name + '-' + Node1.InnerText);
    Node2 := Node1.SelectSingleNode('ns:invoice', NameSpaceMgr);
    MESSAGE(Node2.Name + '-' + Node2.InnerText);
    Node3 := Node2.SelectSingleNode('ns:id', NameSpaceMgr);
    MESSAGE(Node3.Name + '-' + Node3.InnerText);
    Node3 := Node2.SelectSingleNode('abc:name', NameSpaceMgr);
    MESSAGE(Node3.Name + '-' + Node3.InnerText);
    Node3 := Node2.SelectSingleNode('def:name', NameSpaceMgr);
    MESSAGE(Node3.Name + '-' + Node3.InnerText);
    
Sign In or Register to comment.