Read XML File

rickyl76rickyl76 Member Posts: 25
I was hoping someone could help me. I want to be able to read an xml file in code rather than through an XMLPort. I know there are other threads out there on this but they can all get a bit confusing especially as it's an area i'm not overly familiar with. Can someone just give me a quick pointer on how I can read the file and the nodes. I keep falling down when I try it so would like just a basic bit of code that I could follow. Any help would be appreciated

Answers

  • JuhlJuhl Member Posts: 724
    edited 2017-04-22
    Use DotNet XDocument, Automations is the way of the past with RTC.

    Use Enumurator in 2015 and back or in 2016 https://www.hougaard.com/foreach-statement-available-in-nav2016/
    Follow me on my blog juhl.blog
  • ftorneroftornero Member Posts: 524
    You can use something like that:
    GetCurrencies()
    XMLDoc := XMLDoc.XmlDocument;
    
    XMLDoc.Load('http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml');
    
    RemoveNamespace(XMLDoc, XMLDocOut);
    XMLNodeList := XMLDocOut.GetElementsByTagName('Cube');
    Nodes := XMLNodeList.Count;
    FOR i := 0 TO Nodes-1 DO BEGIN
      XMLNode   := XMLNodeList.ItemOf(i);
      XMLAttrib := XMLNode.Attributes;
      XMLNode   := XMLAttrib.GetNamedItem('time');
      IF NOT ISNULL(XMLNode) THEN
        tDate     := XMLNode.InnerText;
      XMLNode   := XMLAttrib.GetNamedItem('currency');
      IF NOT ISNULL(XMLNode) THEN
        tCurrency := XMLNode.InnerText;
      XMLNode   := XMLAttrib.GetNamedItem('rate');
      IF NOT ISNULL(XMLNode) THEN
        tRate     := XMLNode.InnerText;
      MESSAGE('(%1/%2) %3  %4 = %5', i+1, Nodes, tDate, tCurrency, tRate);
    END;
    

    Where RemoveNamespace is:
    RemoveNamespace(XMLDocIn : DotNet "System.Xml.XmlDocument";VAR XMLDocOut : DotNet "System.Xml.XmlDocument")
    // before this function your tag looks like this: <namespace:tagname>sample text</tagname>
    // after this function your tag looks like this: <tagname>sample text</tagname>
    // additionally all namespace references in the head are removed.
    XslTransform :=  XslTransform.XslTransform;
    XMLStyleSheet := XMLStyleSheet.XmlDocument;
    XMLStyleSheet.InnerXml(
    '<?xml version="1.0" encoding="UTF-8"?>' +
    '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">' +
    '<xsl:output method="xml" encoding="UTF-8" />' +
    '<xsl:template match="/">' +
    '<xsl:copy>' +
    '<xsl:apply-templates />' +
    '</xsl:copy>' +
    '</xsl:template>' +
    '<xsl:template match="*">' +
    '<xsl:element name="{local-name()}">' +
    '<xsl:apply-templates select="@* | node()" />' +
    '</xsl:element>' +
    '</xsl:template>' +
    '<xsl:template match="@*">' +
    '<xsl:attribute name="{local-name()}"><xsl:value-of select="."/></xsl:attribute>' +
    '</xsl:template>' +
    '<xsl:template match="text() | processing-instruction() | comment()">' +
    '<xsl:copy />' +
    '</xsl:template>' +
    '</xsl:stylesheet>'
    );
    
    XslTransform.Load(XMLStyleSheet);
    writer := writer.StringWriter();
    XslTransform.Transform(XMLDocIn, nullXsltArgumentList, writer);
    XMLDocOut := XMLDocOut.XmlDocument;
    XMLDocOut.InnerXml(writer.ToString());
    

    And this are the local vars:
    Name	DataType	Subtype	Length
    XMLStyleSheet	DotNet	System.Xml.XmlDocument.'System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    XslTransform	DotNet	System.Xml.Xsl.XslTransform.'System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    writer	DotNet	System.IO.StringWriter.'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    nullXsltArgumentList	DotNet	System.Xml.Xsl.XsltArgumentList.'System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    


  • ftorneroftornero Member Posts: 524
    Sorry I forgot the local vars in Getcurrencies()
    Name	DataType	Subtype	Length
    XMLDoc	DotNet	System.Xml.XmlDocument.'System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    XMLDocOut	DotNet	System.Xml.XmlDocument.'System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    XMLNode	DotNet	System.Xml.XmlNode.'System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    XMLNodeList	DotNet	System.Xml.XmlNodeList.'System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    XMLAttrib	DotNet	System.Xml.XmlAttributeCollection.'System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    i	Integer		
    Nodes	Integer		
    tDate	Text		
    tCurrency	Text		
    tRate	Text		
    
  • FerroFerro Member Posts: 7
    Hello guys, I'm currently refactoring a similar bit of code for the Universal Code Initiative and I need to remove/adapt the dotnet variables:
    procedure RemoveNamespace(XMLDocIn: XmlDocument; XMLDocOut: XmlDocument)
        var
            Writer: Dotnet StringWriter;
            XMLStyleSheet: XmlDocument; // XMLStyleSheet: Dotnet XmlDocument;
            NullXsltArgumentList: Dotnet XsltArgumentList;
            XslTransform: Dotnet XslTransform;
        begin
            XslTransform := XslTransform.XslTransform;
            // XMLStyleSheet := XmlDocument.Create(); //XMLStyleSheet := XMLStyleSheet.XmlDocument;
            XMLStyleSheet := XmlDocument.Create();
            XMLStyleSheet.InnerXml(
              '<?xml version="1.0" encoding="UTF-8"?>' +
              '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">' +
              '<xsl:output method="xml" encoding="UTF-8" />' +
              '<xsl:template match="/">' +
              '<xsl:copy>' +
              '<xsl:apply-templates />' +
              '</xsl:copy>' +
              '</xsl:template>' +
              '<xsl:template match="*">' +
              '<xsl:element name="{local-name()}">' +
              '<xsl:apply-templates select="@* | node()" />' +
              '</xsl:element>' +
              '</xsl:template>' +
              '<xsl:template match="@*">' +
              '<xsl:attribute name="{local-name()}"><xsl:value-of select="."/></xsl:attribute>' +
              '</xsl:template>' +
              '<xsl:template match="text() | processing-instruction() | comment()">' +
              '<xsl:copy />' +
              '</xsl:template>' +
              '</xsl:stylesheet>'
              );
    
            XslTransform.Load(XMLStyleSheet);
            Writer := Writer.StringWriter;
            XslTransform.Transform(XMLDocIn, NullXsltArgumentList, Writer);
            XMLDocOut := XMLDocOut.XmlDocument;
            XMLDocOut.InnerXml(Writer.ToString);
        end;
    

    I've already started refactoring the XMLdocument datatype but I'm completely lost about the other dotnets (StringWriter, XsltArgumentList, XslTransform).

    Does anyone have some experience with this?
  • vaprogvaprog Member Posts: 1,139
    You may not need the function anymore at all. XMLPort got better at handling namespaces, and XML DOM Management provides more functions supporting using namespaces.

    If you need the transform anyway, have a look at Codeunit 6224 "XML DOM Management", specifically function RemoveNamespaces and Codeunit 3038 "DotNet_XslCompiledTransform", if you want to use your own transform.
  • FerroFerro Member Posts: 7
    Yeah, briefly after posting the question here, I found those codeunits with the prefix "Dotnet_" like codeunit DotNet_XslCompiledTransform, DotNet_XsltArgumentList, etc.

    But seeing as they still use dotnet variables I don't think we're supposed to use them when we have Target: "Cloud" in the App.json file right?
  • vaprogvaprog Member Posts: 1,139
    I have been told "You may use those, but must not declare variables of type Dotnet yourself." And standard Dynamics functionality uses them. So if it is ok for MS to use those, it should be of for us to use them.

    But I don't really know, just guessing here.
Sign In or Register to comment.