Options

How to import the data through xmlport when received from Webservice?

chirag_sethichirag_sethi Member Posts: 1
edited 2019-03-05 in NAV Three Tier
I called external web service and when a response was received, I saved the XML file. Now I want to import the data from that XML file into the table. But with the XML file structure I am unable to import
Please let me know how the XML structure will look like? What properties needed to set? Or will these type of files imported only through code?



Codeunit
OBJECT Codeunit 90001 Web Service Test
{
OBJECT-PROPERTIES
{
Date=05-03-19;
Time=19:07:12;
Modified=Yes;
Version List=;
}
PROPERTIES
{
OnRun=BEGIN
WebServiceFunctionA;
END;

}
CODE
{

LOCAL PROCEDURE WebServiceFunctionA@5();
VAR
uriObj@1000 : DotNet "'System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Uri";
Request@1001 : DotNet "'System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Net.HttpWebRequest";
Stream@1002 : DotNet "'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.IO.StreamWriter";
Response@1003 : DotNet "'System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Net.HttpWebResponse";
Reader@1004 : DotNet "'System.xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Xml.XmlTextReader";
document@1005 : DotNet "'System.xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Xml.XmlDocument";
ascii@1006 : DotNet "'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Text.Encoding";
FileMgt@1007 : Codeunit 419;
FileSrv@1008 : Text;
ToFile@1009 : Text;
Xml@1010 : Text;
url@1011 : Text;
SoapAction@1012 : Text;
BEGIN
Xml := '<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance&quot; xmlns:xsd="http://www.w3.org/2001/XMLSchema&quot; xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body>'+
'<GetHolidaysForYear xmlns="http://www.holidaywebservice.com/HolidayService_v2/">'+
'<countryCode>UnitedStates</countryCode>'+
'<year>2019</year>'+
'</GetHolidaysForYear>'+
'</soap:Body></soap:Envelope>';

url := 'http://www.holidaywebservice.com/HolidayService_v2/HolidayService2.asmx';
uriObj := uriObj.Uri(url);
Request := Request.CreateDefault(uriObj);
Request.Method := 'POST';
Request.ContentType := 'text/xml';
SoapAction := 'http://www.holidaywebservice.com/HolidayService_v2/GetHolidaysForYear';
Request.Headers.Add('SOAPAction', SoapAction);
Request.Timeout := 120000;


// Send the request to the webservice
Stream := Stream.StreamWriter(Request.GetRequestStream(), ascii.UTF8);
Stream.Write(Xml);
Stream.Close();

// Get the response
Response := Request.GetResponse();
Reader := Reader.XmlTextReader(Response.GetResponseStream());

// Save the response to a XML
document := document.XmlDocument();
document.Load(Reader);
FileSrv := FileMgt.ServerTempFileName('xml');
document.Save(FileSrv);

// Get from the server
ToFile := FileMgt.ClientTempFileName('xml');
FileMgt.DownloadToFile(FileSrv, ToFile);

// Show the response XML
HYPERLINK(ToFile);
END;

BEGIN
END.
}
}

XMLFILE

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/&quot; xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance&quot; xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;
<soap:Body>
<GetHolidaysForYearResponse xmlns="http://www.holidaywebservice.com/HolidayService_v2/"&gt;
<GetHolidaysForYearResult>
<Holiday>
<Country>UnitedStates</Country>
<HolidayCode>NEW-YEARS-DAY-ACTUAL</HolidayCode>
<Descriptor>New Year's Day</Descriptor>
<HolidayType>Other</HolidayType>
<DateType>Actual</DateType>
<BankHoliday>NotRecognized</BankHoliday>
<Date>2019-01-01T00:00:00</Date>
<RelatedHolidayCode>NEW-YEARS-DAY-OBSERVED</RelatedHolidayCode>
</Holiday>
</GetHolidaysForYearResult>
</GetHolidaysForYearResponse>
</soap:Body>
</soap:Envelope>

Thanks in advance for the help.

Answers

  • Options
    TallyHoTallyHo Member Posts: 383
    edited 2019-03-05
    xmlport is probably possible, use an online xsd generator to generate xsd.
    Afterwards, use this tool to generate nav xml:
    https://mibuso.com/downloads/dynamics-nav-xmlport-generator-v1.3


    Or just do it manually, this isn't a very complicated xml (soap) structure.

    Remove all the stuff that is not needed before importing the xml file with the xmlport:

    TempBlob.Blob.CREATEOUTSTREAM(OutStreamStylesheet);
    TempBlob.Blob.CREATEINSTREAM(InStreamStylesheet);
    OutStreamStylesheet.WRITETEXT('<?xml version="1.0" encoding="UTF-8"?>');
    OutStreamStylesheet.WRITETEXT('<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">');
    OutStreamStylesheet.WRITETEXT('<xsl:output method="xml" encoding="UTF-8" />');
    OutStreamStylesheet.WRITETEXT('<xsl:template match="/">');
    OutStreamStylesheet.WRITETEXT('<xsl:copy>');
    OutStreamStylesheet.WRITETEXT('<xsl:apply-templates />');
    OutStreamStylesheet.WRITETEXT('</xsl:copy>');
    OutStreamStylesheet.WRITETEXT('</xsl:template>');
    OutStreamStylesheet.WRITETEXT('<xsl:template match="*">');
    OutStreamStylesheet.WRITETEXT('<xsl:element name="{local-name()}">');
    OutStreamStylesheet.WRITETEXT('<xsl:apply-templates select="@* | node()" />');
    OutStreamStylesheet.WRITETEXT('</xsl:element>');
    OutStreamStylesheet.WRITETEXT('</xsl:template>');
    OutStreamStylesheet.WRITETEXT('<xsl:template match="@*&quot;>');
    OutStreamStylesheet.WRITETEXT('<xsl:attribute name="{local-name()}"><xsl:value-of select="."/></xsl:attribute>');
    OutStreamStylesheet.WRITETEXT('</xsl:template>');
    OutStreamStylesheet.WRITETEXT('<xsl:template match="text() | processing-instruction() | comment()">');
    OutStreamStylesheet.WRITETEXT('<xsl:copy />');
    OutStreamStylesheet.WRITETEXT('</xsl:template>');
    OutStreamStylesheet.WRITETEXT('<xsl:template match="@*[local-name(.)=''noNamespaceSchemaLocation'']"/>');
    OutStreamStylesheet.WRITETEXT('</xsl:stylesheet>');
    IF ISCLEAR(XMLStyleSheet) THEN
    CREATE(XMLStyleSheet);
    XMLStyleSheet.load(InStreamStylesheet);
    IF ISCLEAR(XMLDestinationDocument) THEN
    CREATE(XMLDestinationDocument);
    XMLSourceDocument.transformNodeToObject(XMLStyleSheet,XMLDestinationDocument);

    OR

    xmldom is just as easy
    https://blogs.msdn.microsoft.com/nav/2010/03/24/how-to-createread-xml-file-from-microsoft-dynamics-nav-without-using-xmlports/

    (use .net iso automation, look at, or just use CU 6224 XML DOM Management).
  • Options
    krikikriki Member, Moderator Posts: 9,096
    [Topic moved from 'NAV/Navision Classic Client' forum to 'NAV Three Tier' forum]

    Regards,Alain Krikilion
    No PM,please use the forum. || May the <SOLVED>-attribute be in your title!


  • Options
    MarkNAV365MarkNAV365 Member Posts: 3
    Hello TallyHo,

    i tried your suggestion to remove the namespaces but was unsuccessful.

    Can you please edit the XML provided by Chirag and update in your code using style sheet?
    And also if we copy the code to remove namespaces in separate function then how will this function
    be called with parameters?

    Your help will be appreciated.

    Thanks!!!
  • Options
    TallyHoTallyHo Member Posts: 383
    The quickest way is using xmldom.
    If you're not acquainted with it, try to search for documentation.
    All the other stuff that sometimes has to be done just to be able to use xmlports is way too much effort.
    Though the newest nav versions have a lot of new fucntionality in xmlports

    Below the code, it is not tested, and based on automation. But dotnet shouldn't be much different.


    Path := '//soap:Envelope/soap:Body/GetHolidaysForYearResponse/GetHolidaysForYearResult/Holiday
    XMLNodeList := XMLDoc.selectNodes(Path);
    FOR i := 0 TO XMLNodeList.length-1 DO BEGIN
    RelatedHolidayCodeVar := GetNodeValue(XMLDoc,STRSUBSTNO('%1/%2',Path,'RelatedHolidayCode'),i);
    end;

    GetNodeValue(XMLDoc : Automation "'Microsoft XML, v3.0'.DOMDocument";Path : Text[1024];NodeNo : Integer) : Text[1024]
    XMLNodeList := XMLDoc.selectNodes(Path);
    IF XMLNodeList.length <> 0 THEN BEGIN
    XMLNode := XMLNodeList.item(NodeNo);
    EXIT(XMLNode.text);
    end;
    END ELSE
    ERROR('not found');
  • Options
    ftorneroftornero Member Posts: 522
    Hello @marknav365,

    This is the function to remove Namespaces for NAV2013 and up:
    
    RemoveNamespace(XMLDocIn : DotNet "System.Xml.XmlDocument";VAR XMLDocOut : DotNet "System.Xml.XmlDocument")
    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());
    

    The parameters are:
    Var	Name	DataType	Subtype	Length
    No	XMLDocIn	DotNet	System.Xml.XmlDocument.'System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    Yes	XMLDocOut	DotNet	System.Xml.XmlDocument.'System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    

    XMLDocIn and XMLDocOut could be the same var.

    And the vars are:
    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'	
    
  • Options
    MarkNAV365MarkNAV365 Member Posts: 3
    Thanks ftornero for your help. It worked fine.

    ORIGINAL XML
    <?xml version="1.0" encoding="utf-8"?>
    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/&quot; xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance&quot; xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;
    <soap:Body>
    <GetHolidaysForYearResponse xmlns="http://www.holidaywebservice.com/HolidayService_v2/"&gt;
    <GetHolidaysForYearResult>
    <Holiday>
    <Country>UnitedStates</Country>
    <HolidayCode>NEW-YEARS-DAY-ACTUAL</HolidayCode>
    <Descriptor>New Year's Day</Descriptor>
    <HolidayType>Other</HolidayType>
    <DateType>Actual</DateType>
    <BankHoliday>NotRecognized</BankHoliday>
    <Date>2019-01-01T00:00:00</Date>
    <RelatedHolidayCode>TEST1</RelatedHolidayCode>
    </Holiday>
    </GetHolidaysForYearResult>
    </GetHolidaysForYearResponse>
    </soap:Body>
    </soap:Envelope>

    AFTER REMOVING NAMESPACES
    <?xml version="1.0" encoding="utf-16"?>
    <Envelope>
    <Body>
    <GetHolidaysForYearResponse>
    <GetHolidaysForYearResult>
    <Holiday>
    <Country>UnitedStates</Country>
    <HolidayCode>NEW-YEARS-DAY-ACTUAL</HolidayCode>
    <Descriptor>New Year's Day</Descriptor>
    <HolidayType>Other</HolidayType>
    <DateType>Actual</DateType>
    <BankHoliday>NotRecognized</BankHoliday>
    <Date>2019-01-01T00:00:00</Date>
    <RelatedHolidayCode>TEST1</RelatedHolidayCode>
    </Holiday>
    </GetHolidaysForYearResult>
    </GetHolidaysForYearResponse>
    </Body>
    </Envelope>


    Now i am trying the other way, i.e. Third Party tool will call the web service published in NAV by sending file in XML format which will be stored in NAV tables.

    For that i have published the codeunit with function that will have parameter as Big Text

    NAVWebService1.SetGlobals(Payload);
    NAVWebService1.RUN;

    Codeunit NAVWebService1
    In this codeunit, Big Text is stored as Global variable using function SetGlobals and then running the codeunit using RUN

    function definition

    LOCAL ImportRequestFromWebService(PayloadXML : BigText)
    CLEAR(XMLDocIn);
    CLEAR(XmlInStream);
    CLEAR(XmlOutStream);

    XMLDocIn := XMLDocIn.XmlDocument;

    TempBlob.INIT;
    TempBlob.Blob.CREATEOUTSTREAM(XmlOutStream);
    PayloadXML.WRITE(XmlOutStream);
    TempBlob.INSERT;
    TempBlob.CALCFIELDS(Blob);
    TempBlob.Blob.CREATEINSTREAM(XmlInStream);

    XMLDocIn.Load(XmlInStream);
    XMLDocIn.Save('D:\TestFile.xml');

    I am testing it using Wizdler.
    In image Wizdler 1, the highlighted part is copied as an xml
    In image Wizdler 2, the highlighted error.

    Request you to help to solve this issue.

    Thank You!!!
  • Options
    ftorneroftornero Member Posts: 522
    Hello @marknav365,

    If you want to send the XML in the image Wizdler1.jpg, I think that you need to wrap the second Envelop with:

    <![CDATA[]]>

    Regards.
  • Options
    MarkNAV365MarkNAV365 Member Posts: 3
    It worked as expected. Thank You so much for the help.
  • Options
    vnprocvnproc Member Posts: 41
    Hi MarkNAV365

    After the Webserver change port 443, I could not connect to the Webservice
    Please give me a solution. Thanks a lotfqb29h4cu0uj.png


Sign In or Register to comment.