xsharp.eu • XML-Parser System.XML
Page 1 of 1

XML-Parser System.XML

Posted: Fri Dec 31, 2021 12:25 pm
by hsg
Moin,

ich bin gerade am Verzweifeln: Ich muss ein Im-/Export von Daten in einem vorgegeben XML-Format schreiben und dachte, ich nutze dafür die System.XML Lib.
Im ersten Schritt wollte ich erst mal den Importer schreiben und dachte, dass kann ja nicht so schwer werden. Doch leider scheitere ich schon sehr früh:
Um zu prüfen, ob die Datei das gewünschte Datenformat habe, muss ich mir einen bestimmten Knoten im XML-Baum ansehen.
Laut XML-Spy funktioniert bei meiner Beispieldatei der XPath-Ausdruck "GAEB/Award/DP" Der Debugger von XML-Spy liefert mir dann den korrekten Knoten und dessen Value.

Laden tue ich die XML-Datei über folgendem Code:

Code: Select all

		settings 			:= XmlReaderSettings{}
		settings:IgnoreWhitespace 	:= TRUE 
		settings:ASYNC			:= FALSE
		xr 				:= XmlReader.Create(cFile, settings)
		oMXML:Load( xr )

oMXML ist dabei vom Typ XMLDocument.
Das Suchen nach dem Knoten sieht wie folgt aus:

Code: Select all

      oNode := oMXML:selectSingleNode( "GAEB/Award/DP" )
      IF oNode != NULL_OBJECT
        cVal	:= oNode:Value
     END IF
Obwohl ich im Debugger beim oMXML plausiblen Inhalt sehe, geht das Selektieren des Knoten schief und ich bekomme immer NULL zurück.

Wer kann mich mal auf den richtigen Weg schubsen?
Guten Rutsch und ein erfolgreiches Jahr 2022 für alle!
Gruß
Jörg

XML-Parser System.XML

Posted: Fri Dec 31, 2021 1:05 pm
by wriedmann
Hallo Jörg,
ich verwende diesen Code hier:

Code: Select all

protected method _FindNode( oXmlNode as XmlNode, cName as string ) as XmlNode
local oReturn as XmlNode

oReturn	:= null
if oXmlNode:Name:ToLower() == cName
  oReturn := oXmlNode
else
  foreach oNode as XmlNode in oXmlNode:ChildNodes
    oReturn := self:_FindNode( oNode, cName )
    if oReturn != null
      exit
    endif
  next
endif

return oReturn
Dieser Code ist Teil einer eigenen Klasse, mit der ich die in Italien obbligatorische elektronische Rechnung auswerte. Wenn es notwendig ist, kann ich auch anderen Code bereitstellen. Diese Methode ist aber das Kernstück beim Zerlegen des XML-Dokumentes.
Wolfgang
P.S. sorry, bin aktuell in Urlaub, daher kann eine eventuelle Antwort etwas dauern

XML-Parser System.XML

Posted: Fri Dec 31, 2021 1:25 pm
by hsg
Hatte schon über ähnliches nachgedacht, aber das ist ja eigentlich nicht Sinn der XML-Schnittstelle. Daher hatte ich gehofft, es über die vorhandenen Methoden wie SelectSingleNode oder SelectNodes erledigen zu können.

Gruß
Jörg

XML-Parser System.XML

Posted: Sat Jan 01, 2022 8:21 am
by wriedmann
Hallo Jörg,
wenn die XML-Dateien aus einer einzigen Quelle kommen, dann mag ein starres Auslesen schon funktionieren.
Ich ziehe aber die größere Fehlertoleranz einer solchen Suche vor.
Wolfgang

XML-Parser System.XML

Posted: Sat Jan 01, 2022 11:22 am
by VR
Für das Importieren von XML Dateien würde ich die XDocument Klasse empfehlen (Namespace System.Xml.Linq). Da kann man dann mit Linq auf die XML Knoten zugreifen. Hier ein Beispiel zu den wichtigsten Methoden aus dem Informinds XSharpExamples:

https://github.com/InfomindsAg/XSharpEx ... amples.prg

Zum Schreiben von XML Dateien mit XDocument gibt's auch ein Beispiel:

https://github.com/InfomindsAg/XSharpEx ... amples.prg

Kleiner Tipp noch: wenn man beim Suchen der Knoten mit Namen Null statt des gewünschten Elements zurück bekommt, könnte das an einem XML-Namespace liegen. (https://www.w3schools.com/xml/xml_namespaces.asp)

Grüße

Volkmar

XML-Parser System.XML

Posted: Sat Jan 01, 2022 3:23 pm
by hsg
Hmmm, ich erinnere mich schwach an das Thema Namespace.
Die XML-Datei fängt wie folg an:

Code: Select all

<?xml version="1.0" encoding="UTF-8"?>
<GAEB xmlns="http://www.gaeb.de/GAEB_DA_XML/200407">
Ist also eigentlich kein vollständiger Namespace, wie ich das sehe. Habe trotzdem mal meine Laderoutine wie folgt geändert:

Code: Select all

		settings 			:= XmlReaderSettings{}
		settings:IgnoreWhitespace 	:= TRUE 
		settings:ASYNC			:= FALSE
		xr 				:= XmlReader.Create(cFile, settings)
		oMXML:Load( xr )     
		xns				:= XmlNamespaceManager{oMXML:NameTable}
		IF oMXML:DocumentElement <> NULL
			oRoot		     := oMXML:DocumentElement
			FOR i := 0 TO oRoot:Attributes:Count - 1 
				oAtt		 := oRoot:Attributes[i]
				IF oAtt:Name == "xmlns" 
					xns:AddNamespace(oMXML:NameTable:ToString(),oAtt:Value)
				END IF
			NEXT
	        lResult  := TRUE                 
		END IF
und gebe den NameSpaceManager beim SelectSingleNode mit an: Gleiches Ergebnis wie bisher (also NULL)
Wenn nicht noch ein paar Tipps mir auf den richtigen Weg bringen, werde ich mir die XDocument Klasse mal näher ansehen.
Oder die Knoten selbst suchen.

Frohes Neues Allen!
Jörg

XML-Parser System.XML

Posted: Tue Jan 04, 2022 3:26 pm
by hsg
So, ich habe eine Lösung gefunden: Der XPath-Ausdruck den ich bisher benutzt hatte, scheint hier nicht zu funktionieren. Stattdessen rufe ich jetzt SelectSingleNode wie folgt auf:

Code: Select all

....
oNode := oMXML:SelectSingleNode(GetXPathFromRoot( "DP" )) 
...
mit:

METHOD GetXPathFromRoot( cFeld AS STRING) AS STRING
RETURN "//*[local-name()=""" + cFeld + """]"