WebService Antwort über XMLPort importieren

3. Juli 2008 16:38

Hallo,

bin gerade dabei, einen Webservice in Nav 4 SP3 einzubinden.
Die Abfragen funktionieren und die Antworten des Webservice kann ich auch in einer XML datei speichern.

Nun möchte ich die Antwort
z.B.
Code:
  <?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>
- <GetGeoIPResponse xmlns="http://www.webservicex.net">
- <GetGeoIPResult>
  <ReturnCode>1</ReturnCode>
  <IP>85.168.234.33</IP>
  <ReturnCodeDetails>Record Found</ReturnCodeDetails>
  <CountryName>FRANCE</CountryName>
  <CountryCode>FR</CountryCode>
  </GetGeoIPResult>
  </GetGeoIPResponse>
  </soap:Body>
  </soap:Envelope>


in einen XMLPort einlesen.

Das Einlesen der Webservice Antwort und schreiben in eine Datei klappt:
Code:
CREATE(XmlDoc); //'Microsoft XML, v6.0'.DOMDocument
XmlDoc.async := FALSE;
XmlDoc.load('C:\Request.xml');

CREATE(EHXmlHttp); //'Microsoft XML, v6.0'.XMLHTTP60
XmlHttp.open('POST','http://xxx.asmx',0);
XmlHttp.setRequestHeader('Content-type','text/xml');
XmlHttp.setRequestHeader('SOAPAction','http://xxx');
EHXmlHttp.send(XmlDoc);

XmlDoc.load(EHXmlHttp.responseXML);
XmlDoc.save('C:\Result.xml');


Nun möchte ich aber das als INSTREAM oder ähnlich einlesen und an einen XMLPort weiterleiten. In etwas so:

Code:
ResponseFile.CREATETEMPFILE;
ResponseFile.CREATEINSTREAM(InStrm);
InStrm := XmlHttp.responseStream();

XMLPORT.IMPORT(XMLPORT::XMLResult, InStrm);


Kann mir da jemaind helfen???

Danke,
Naviii

3. Juli 2008 22:27

mhm, schon lange her, dass ich was mit XMLPorst gemacht habe. aber in diesem Zusammenhang, würde ich eher die Automation XMLDOM vavorisieren, da du auch dort direkt den Webservice abrufen kannst.
Schau dir mal die Codeunits zum Thema XML an. Auf der M$ Seite gabs auch mal ein Beispiel zu Navision und Webservice. Da haben sie glaub ich auch XMLDOM benutzt.

4. Juli 2008 08:32

Hallo garak,

vielen Dank für den Hinweis auf XMLDOM, allerdings arbeite ich damit doch schon *verwirrt bin*.

4. Juli 2008 08:50

Hallo Naviii!

vielleicht funktioniert folgendes:

Code:
Filename:='C:\Result.xml';

IF XMLFile.OPEN(Filename) THEN BEGIN
  XMLFile.CREATEINSTREAM(Stream);
  XMLPort.SETSOURCE(Stream);
  IF NOT XMLPort.IMPORT THEN
    ERROR('Die Datei '%1' konnte nicht importiert werden.',Filename);
END ELSE
  ERROR('Die Datei '%1' konnte nicht geöffnet werden.',Filename);
  • XMLFile wäre eine Variable vom Typ File.
  • XMLPort wäre eine Variable vom Typ XMLPort. Als Subtype sollte dein XMLport hinterlegt sein.
  • Stream ist eine Variable vom Typ InStream.

Gruß, Marc

4. Juli 2008 09:21

Hallo Marc,

vielen Dank für den Tipp.
Leider klappt es nicht, die erste Error Meldung ".. konnte nicht importiert werden" wird ausgegeben.

Ich versuche es weiter...

4. Juli 2008 09:34

Ich nochmal,

liegt der fehlgeschlagene Import vielleicht daran, wie der Inhalt der Response.XML Datei aussieht?

Code:
  <?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>
- <GetGeoIPResponse xmlns="http://www.webservicex.net">
- <GetGeoIPResult>
  <ReturnCode>1</ReturnCode>
  <IP>85.168.234.33</IP>
  <ReturnCodeDetails>Record Found</ReturnCodeDetails>
  <CountryName>FRANCE</CountryName>
  <CountryCode>FR</CountryCode>
  </GetGeoIPResult>
  </GetGeoIPResponse>
  </soap:Body>
  </soap:Envelope>

4. Juli 2008 10:19

Es könnte auch daran liegen. Doch ohne XMLport kann man das nur schwer nachvollziehen...

4. Juli 2008 10:59

Stimmt.

ich denke auch, dass es am XMLPort liegt.
Hier zunächst der XMLPort:

Code:
TagName            TagType   SourceType   DataSource
GetGeoIPResult   Element          Table        <XMLTestIPAbfrage>(XMLIPImport)
ReturnCode     Element    Field     <XMLTestIPAbfrage>::ReturnCode
IP                   Element          Field         <XMLTestIPAbfrage>::IP
ReturnCodeDetails   Element   Field <XMLTestIPAbfrage>::ReturnCodeDetails
CountryName   Element          Field       <XMLTestIPAbfrage>::CountryName
CountryCode   Element          Field   <XMLTestIPAbfrage>::CountryCode


Die Webservice Antwort nochmal:
Code:
<?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>
<GetGeoIPResponse  xmlns="http://www.webservicex.net">
<GetGeoIPResult>
<ReturnCode>1</ReturnCode>
<IP>85.168.234.33</IP>
<ReturnCodeDetails>Record Found</ReturnCodeDetails>
<CountryName>FRANCE</CountryName>
<CountryCode>FR</CountryCode>
</GetGeoIPResult>
</GetGeoIPResponse>
</soap:Body>
</soap:Envelope>


Es kommt nach dem Import die Fehlermeldung "Das Element <Envelope> kann in der Objektbeschreibung nicht gefunden werden".
Macht ja auch Sinn, denn den Tag <soap:Envelope> habe ich im XMLPort ja auch nicht angegeben.

Wenn ich aber nun diesen Tag im XMLPort vor dem ersten Tag "GetGeoIPResult" einfüge, kommt die gleiche Fehlermeldung.

Liegt also wirkich am XMLPort.

Allerdings habe ich mich nun ja von dem ursprünglichen Problem entfernt.
Das war ja folgendes:
Vorausgesetzt, der Import über die gespeicherte XML-Datei funktioniert,
also
1. XML request abschicken
2. XML response als Datei speichern
3. diese Datei wieder als InStream einlesen und über XML Port importieren

dachte ich mir, dass der "Umweg" über das Speichern der response in eine Datei um sie dann sofort wieder auszulesen ja nicht unbedingt sein muss. Deshalb ja die ursprüngliche Frage, ob die XML response direkt in einen InStream geleitet und dann über den XMLPort direkt (ohne zwischenspeichern auf Festplatte) eingelesen werden kann.

Ich hoffe, ihr verliert nicht die Lust daran, mir etwas zu helfen ;-(.

4. Juli 2008 13:08

Naviii hat geschrieben:[...]dachte ich mir, dass der "Umweg" über das Speichern der response in eine Datei um sie dann sofort wieder auszulesen ja nicht unbedingt sein muss.

Ok, da muss ich passen. Genau diese Frage habe ich mir auch mal gestellt. Musste dann auch den "Umweg" über eine zwischengespeicherte Datei gehen.

Wenn jemand eine Idee hat: Ich würde auch gerne wissen, wie es funktioniert. :-)

Gruß, Marc

Re: WebService Antwort über XMLPort importieren

17. Dezember 2008 01:38

Hallo Zusammen.
Ich habe derzeit genau das selbe problem. Habe die erhaltene datei einfach perxml port entsprechend der response datei nachgebaut und in nav per xmlport.import einlesen wollen. leider erhalte ich genau die selben rückmeldungen, wie envelope kann nicht gefunden werden oder dass der namespace nicht im document ist.

Hat vielleicht jemand hierzu neue Erkenntnis gewinnen können?
Meine Erfahrungsfragen .... am xml port selbst.... oder dem Abruf der daten per soap, zusätzlich zum definierten xmlport als reine Datenbeschreibung quasi?!? d.h. nach meinem Verständins sollte es doch einfach möglich sein per xmlport ein file mit einer einfachen struktur in eine nav tabelle einzulesen, oder?

LIegt es vielleicht an dem Soap Connetcor und Initialiser den man dazu separat vielleicht als automation einbinden muss. wie hier in mit nav verwendet viewtopic.php?f=35&t=3993&hilit=soap Quasi die abruf-verbindung zur der wsdl und xsd Beschreibung der gelieferten xml daten?

Bin für jeden Tipp dankbar. :-?

Gruß
Martin

Re: WebService Antwort über XMLPort importieren

17. Dezember 2008 12:18

Ein Auzug aus dem Designersguide....

XMLports do not handle XML documents that:
• modify existing data in the database.
• find and delete data in the database.
• query the database for data (item catalog information, for example).
If you need to work with an incoming document of one of these types, you can do so
using C/AL code and by carrying out the database manipulation necessary to achieve
the desired result.

... d.h. man muss einen XML Import immer manuell realisieren und kann den XML-Port selbst nicht wie den Dataport zum Import von Daten nutzen?!?

Re: WebService Antwort über XMLPort importieren

17. Dezember 2008 14:19

Hat jemand dazu vielleicht eine Idee?!?.... wäre für jeden Tipp dankbar....

Re: WebService Antwort über XMLPort importieren

17. Dezember 2008 21:18

Ich glaube, dass hier wäre ein Hinweis. Siehen gleich der erste Absatz....

http://blogs.msdn.com/german_nav_develo ... l-dom.aspx

Ist das so, dass man die XML.Ports nicht für einen Datenimport der per SOAP zurückgelieferten Daten nutzen kann?

Bitte um etwas Erfahrungsaustausch :roll:

Gruß, Martin

Re: WebService Antwort über XMLPort importieren

27. Januar 2009 07:30

enttäuschende Antworten :-|

Re: WebService Antwort über XMLPort importieren

27. Januar 2009 09:26

Hallo Martin,

ich habe die Erfahrung gemacht, das die XML-Ports an vielen Stellen Einschränkungen haben, die sie für die Benutzung teilweise ausschließen. Wenn man sich ein wenig mit dem MSXML- Objekten beschäftigt, gelingt die Verarbeitung der XML-Daten i.d.R. genauso schnell wie mit einem XML-Port. Der Vorteil von MSXML ist, das es auf jedem PC mit NAV-Client vorhanden sein sollte, denn NAV benutzt diese Schnittstelle selbst (z.B. GDPDU), und das man alle Möglichkeiten hat aus die XML-Tags zuzugreifen, und diese zu manipulieren.

Gruß, Fiddi

P.S.: Web-Services und XML waren bisher nicht unbedingt die Hauptthemen von NAV-Programmierern, daher gibt es nicht so viele mit Erfahrungen in dem Bereich. Es kann also sein, das eine Frage in diesem Bereich untergeht, weil gerade keiner der XML-Spezies Online war.
Zuletzt geändert von fiddi am 27. Januar 2009 09:31, insgesamt 1-mal geändert.

Re: WebService Antwort über XMLPort importieren

27. Januar 2009 09:27

Martin Glück hat geschrieben:enttäuschende Antworten :-|

Wir (anderen) würden ja gerne helfen, aber wer es selber nicht ausprobiert (weil nie gebraucht) hat, der kann leider nichts dazu beitragen ...

Re: WebService Antwort über XMLPort importieren

9. Februar 2009 00:51

Hallo,

weil unser Know-how im Bereich Navision liegt, ist die Frage wichtig: wie kann man in der vorhandenen XML Struktur auf die notwendigen Daten zugreifen.

Ich finde es nicht rational, den Umweg mit dem XML Port zu machen, weil die Daten durch den Aufruf XMLDoc.load(…) schon in Navision zur Verfügung stehen. Es ist egal, woher die XML Struktur kommt – aus einer Webservice Antwort oder aus einer Datei. In Navision landet sich diese durch den oben genannten Aufruf. Ich habe einige Erfahrungen mit dem Importieren von XML Strukturen in Navision. Es gab keine zwei gleichen Aufgabenstellungen. Zuerst muss man klar definieren, wie die Struktur bearbeitet werden soll, um auf die gesuchten Daten zu kommen. Hier bittet Navision viele Möglichkeiten, aber gebraucht werden nur wenige.

Obwohl ich die Aufgabenstellung nicht kenne, ist es aus der Struktur ersichtlich, dass die Daten zur Auswertung in den fünf Nodes liegen: <ReturnCode>, <IP>, <ReturnCodeDetails>, <CountryName>, <CountryCode>. Mann sieht auch, dass diese Nodes eine Liste auf der gleichen Ebene bilden. Diese Liste ist dem Node <GetGeolPResult> untergeordnet. Alles ähnlich der Zuordnung von DataItems z.B. in einem Bericht.

Code:
<?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>
      <GetGeoIPResponse xmlns="http://www.webservicex.net">
         <GetGeoIPResult>
            <ReturnCode>1</ReturnCode>
            <IP>85.168.234.33</IP>
            <ReturnCodeDetails>Record Found</ReturnCodeDetails>
            <CountryName>FRANCE</CountryName>
            <CountryCode>FR</CountryCode>
         </GetGeoIPResult>
      </GetGeoIPResponse>
   </soap:Body>
</soap:Envelope>


Jetzt überlege ich mir, wie am besten durch die Struktur zu navigieren ist. Auf der obersten Ebene sind zwei Nodes - <xml> und <soap:Envelope>. Zuerst sollte der letzte <soap:Envelope> erreicht werden. Dann sollten drei Sprünge auf jeweils untergeordneten Node gemacht werden, bis <GetGeolPResult> erreicht ist. Von diesem Node sollte die Liste von untergeordneten Nodes durchgegangen werden. Abhängig vom Wert in einem Node können die Daten weiter ausgewertet werden.

Für den Test habe ich die Struktur in einer Datei gespeichert. Nach solcher Planung sieht der ganze Code sehr bescheidend aus:

Code:
// Variablen
// Name        DataType   Subtype
// XMLDoc      Automation 'Microsoft XML, v4.0'.DOMDocument40
// XMLNodeList Automation 'Microsoft XML, v4.0'.IXMLDOMNodeList
// XMLNode     Automation 'Microsoft XML, v4.0'.IXMLDOMNode
// Count       Integer

CREATE(XMLDoc);
XMLDoc.load('C:\test_XML.xml');

// <soap:Envelope>.
XMLNode := XMLDoc.lastChild;

// <soap:Body>
XMLNode := XMLNode.firstChild;

// < GetGeoIPResponse >
XMLNode := XMLNode.firstChild;

// < GetGeoIPResult >
XMLNode := XMLNode.firstChild;

// Untergeordnete Nodes von < GetGeoIPResult >
XMLNodeList := XMLNode.childNodes;
FOR Count := 1 TO XMLNodeList.length() DO BEGIN
  XMLNode := XMLNodeList.nextNode();
  MESSAGE('Name: ' + XMLNode.nodeName + '; Value: ' + XMLNode.text);
END;

Mit den in Navision vorhandenen Werkzeugen ist es auch nicht problematisch, die komplexeren XML Strukturen zu bearbeiten.

Gruß, Michael

Re:

8. September 2009 12:41

Hallo Naviii, hallo Marc,
und alle andere Interessierten :-)

Problem
Marc Teuber hat geschrieben:
Naviii hat geschrieben:[...]dachte ich mir, dass der "Umweg" über das Speichern der response in eine Datei um sie dann sofort wieder auszulesen ja nicht unbedingt sein muss.

Ok, da muss ich passen. Genau diese Frage habe ich mir auch mal gestellt. Musste dann auch den "Umweg" über eine zwischengespeicherte Datei gehen.

Wenn jemand eine Idee hat: Ich würde auch gerne wissen, wie es funktioniert. :-)

Gruß, Marc


Lösung
Ich habe gerade beim Recherchieren etwas gefunden, das könnte das Problem mit dem zwischenspeichern lösen.
How to consume a webservice with XMLports and HTTP POST
Am Ende des ersten Beitrags schreibt JohnP im Code:
JohnP hat geschrieben://setup the temporary table so that we can handle the XML without saving it to disk first
//create a couple of streams to transfer the data in and out of the BLOB field


Wenn ich den Code (und sein Kommentar) richtig verstanden habe, arbeitet er mit einer Tabelle Name = TempBlob die nur ein Feld (Name = Blob) enthält vom Typ "Blob". In dieser werden die Daten zwischengespeichert. Wenn das so klappt, ist das auch wesentlich Performanter, da die Tabelle im Code Temporär verwendet wird und nur im Arbeitsspeicher ist!