September 19, 2021, 07:45:28

Neuigkeiten:

Wenn ihr euch für eine gute Antwort bedanken möchtet, im entsprechenden Posting einfach den Knopf "sag Danke" drücken!


Import von XML

Begonnen von Bopi, Juli 24, 2020, 11:46:14

⏪ vorheriges - nächstes ⏩

Bopi

Ich habe noch keine Erfahrung betreffend xml.
Hier mein Problem: Die xml-Datei hat am Anfang einen Tag, welcher die Info zum Schema enthält.
Ich lade die Datei in den Speicher und versuche die einzelnen Tags auszulesen.
Solange der Tag mit dem Schema keine Informationen enthält oder nicht vorhanden ist, funktioniert das wie gewünscht. Aber mit den Schema Informationen tut sich nichts, d.h. Access erkennt keine ChildNodes.

Beispiel der xml:
<?xml version="1.0"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.054.001.04" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:camt.054.001.04 camt.054.001.04.xsd">
<BkToCstmrDbtCdtNtfctn>
<GrpHdr>
<MsgId>2020061775204228731867</MsgId>
<CreDtTm>2020-06-17T23:33:09</CreDtTm>
<MsgPgntn>
<PgNb>1</PgNb>
<LastPgInd>true</LastPgInd>
</MsgPgntn>
<AddtlInf>SPS/1.6/PROD</AddtlInf>
</GrpHdr>
<Ntfctn>
<Id>20200617375204228731887</Id>
<CreDtTm>2020-06-17T23:33:09</CreDtTm>...
Sieht die 2. Zeile dann so aus: <Document>, dann funktioniert es, aber nicht wenn es so wie oben aussieht.
Kann mir das jemand erklären, oder aufzeigen was ich falsch mache?

Hier mein Code, (beim Laden des Formulars):

Private Sub Form_Load()
Dim objXMLNode As IXMLDOMNode
Dim nodeBook As IXMLDOMNode
Dim lstNodes As IXMLDOMNodeList

          Set objXML = New MSXML2.DOMDocument60
          objXML.validateOnParse = True           'Struktur und Daten beim Laden prüfen
          objXML.SetProperty "SelectionLanguage", "XPath"             'echtes XPath verwenden um Nodes zu selektieren
          'Dokument laden
          If Not objXML.Load(Application.CurrentProject.Path & strFile) Then
                    MsgBox "Fehler beim Laden des Dokuments." & vbCrLf _
                              & "Grund: " & objXML.parseError.reason & vbCrLf _
                              & "Zeile: " & objXML.parseError.Line, vbOKOnly Or vbExclamation, "Fehler"
                    Set objXML = Nothing
          End If
          Me.txtPfad = Application.CurrentProject.Path & strFile
          Me.txtXML = objXML.XML
          Set XMLNodes = objXML.getElementsByTagName("*")
          Set lstNodes = objXML.selectNodes("//Id")
          For Each nodeBook In lstNodes
                    Debug.Print fullName(nodeBook) & ": " & nodeBook.Text
          Next
         
End Sub

txtPfad und txtXML sind Felder auf dem Formular.
fullName ist eine kleine Funktion, welche Parent und Child Adresse des Knotens zurückgibt:
Public Function fullName(node As MSXML2.IXMLDOMNode) As String

          If node.parentNode Is Nothing Then
                    fullName = "/"
          Else
                    fullName = fullName(node.parentNode) & "/" & node.nodeName
          End If
         
End Function

crystal

Und was passiert, wenn du
objXML.validateOnParse = False
setzt?

(Der XML-Parser, der in Access benutzt wird, überprüft/berücksichtigt möglicherweise nicht die Direktiven/Regeln, die im <Document>-Statement angegeben werden. Wäre vielleicht auch zu viel verlangt, weil dann jeweils Direktiven nachgeladen werden müssten.)

Oder liegt es hier:
                    Debug.Print fullName(nodeBook) & ": " & nodeBook.Text
was vielleicht lauten sollte
                    Debug.Print fullName(nodeBook) & ": " & fullname(nodeBook).Text
?

Gruß,
crystal
Wer Fehler in meinen Antworten findet, darf sie behalten, muss sie aber kommentieren. ;-)
Dies ist keineswegs arrogant gemeint, sondern soll nur unterstreichen, dass meine Antworten - natürlich - nicht immer fehlerfrei sind und sein können.
Devise: bitte immer erst selbst probieren!

Aus gesundheitlichen Gründen nur noch selten dabei...

Bopi

Vielen Dank für Deine Antwort.
Ersteres habe ich schon getestet. Ändert aber nichts.
Zweiteres werde ich testen, könnte eine Antwort sein.
Ich bin inzwischen auf einen möglichen Lösungsansatz gestossen. Wenn der erfolgreich ist, lasse ich es Euch wissen.

Bopi

Es hat eine Weile gedauert. Ich habe mich zuerst etwas tiefer in die Materie xml eingearbeitet um zu verstehen was da vor sich geht.
Den Fehler habe ich jetzt loklisieren können aber leider noch nicht lösen. Der Fehler ist, dass Access die URL der Schema Datei nicht richtig interpretiert. Es sucht die xsd Datei im selben lokalen Ordner in dem die xml gespeichert ist. Dies obwohl die Adresse richtig hinterlegt ist.
Meiner Meinung nach gibt es zwei Lösungsansätze:
Erstens könnte man Access dazu  bringen, die xsd zu ignorieren, Zweitens könnte man Access dazu bringen die Adresse der xsd richtig zu interpretieren.
Kann mir da jemand weiterhelfen?

PhilS

Zitat von: Bopi am August 26, 2020, 10:40:53Erstens könnte man Access dazu  bringen, die xsd zu ignorieren, Zweitens könnte man Access dazu bringen die Adresse der xsd richtig zu interpretieren.
Ich kenne mich nicht wirklich mit dem Thema aus, aber die Dokumentation des DOMDocument60.schemas Property scheint aufzuzeigen, wie du ein Schema explizit zuweisen kannst.
Access DevTools - Find and Replace
Komfortables Suchen und Ersetzen in den Entwurfseigenschaften von Access-Objekten. In Abfragen, Formularen, Berichten und VBA-Code - Überall und rasend schnell!

ebs17

ZitatErstens könnte man Access dazu  bringen, die xsd zu ignorieren, Zweitens könnte man Access dazu bringen die Adresse der xsd richtig zu interpretieren.
Kann mir da jemand weiterhelfen?
Die XSD ist die Definition, wie die XML anzulegen und umgedreht wie sie zu lesen ist. Das versetzt einen z.B. in die Lage, die XML komplett in einem Rutsch per Standardimport in eine oder mehrere Datenbanktabellen zu importieren. Datenbanktabellen lesen und auswerten ist sicher einfacher und schneller, als sich durch Knoten im XML per VBA zu hangeln, zumindest wenn man mehrere bis viele Informationen benötigt.
Also würde ich unbedingt der zweiten Variante nachgehen.
Mit freundlichem Glück Auf!

Eberhard

Bopi

Zitat von: PhilS am August 26, 2020, 12:35:34Ich kenne mich nicht wirklich mit dem Thema aus, aber die Dokumentation des DOMDocument60.schemas Property scheint aufzuzeigen, wie du ein Schema explizit zuweisen kannst.

Das ist der Weg den ich zur Zeit verfolge.

Bopi

Zitat von: ebs17 am August 26, 2020, 13:02:33Die XSD ist die Definition, wie die XML anzulegen und umgedreht wie sie zu lesen ist. Das versetzt einen z.B. in die Lage, die XML komplett in einem Rutsch per Standardimport in eine oder mehrere Datenbanktabellen zu importieren. Datenbanktabellen lesen und auswerten ist sicher einfacher und schneller, als sich durch Knoten im XML per VBA zu hangeln, zumindest wenn man mehrere bis viele Informationen benötigt.
Also würde ich unbedingt der zweiten Variante nachgehen.

Das ist mir inzwischen auch klar. Der Aufbau der xml beinhaltet Kopfdaten und Detaildaten die in einer 1:n Beziehung stehen. Deshalb denke ich muss ich mich durch die Knoten hangeln. Daher werde ich versuchen den zweiten Weg zu gehen. Ich habe eine Idee dazu. Mal sehen ob es funktioniert.

ebs17

ZitatIch habe eine Idee dazu.
Ich hätte folgende, die in Ansätzen auch schon funktioniert hat - aber ich hatte noch kein richtiges Projekt als Herausforderung, um das in Praxisvielfalt testen zu können.

Zitatin einer 1:n Beziehung
Mit Access, zumindest ab Acc2010, kann man sehr gut auch mehrere Tabellen in eine XML exportieren, siehe dazu auch die CreateAdditionalData-Methode. Dabei kann man sich wahlweise auch zusätzlich die XSD erzeugen lassen.
Somit hätte man XML und XSD, basierend auf dem benötigten Modell für einen Import (Umkehrung des Exports).

Jetzt müsste man nur die vorhandene XML an die eigenerzeugte Konstruktion annähern.

Wie schon angedeutet: Mit einigen Modelldaten hat das schon mal geklappt, ein harter Praxistest wäre interessant.
Mit freundlichem Glück Auf!

Eberhard

Bopi

Meine Idee war eine lokale xsd zu erstellen, die original xml mittels xslt zu transformieren und dabei die uri usw. zu überschreiben mit der lokalen adresse. Das lässt sich auch alles machen. Aber mein eigentliches problem ist damit leider auch nicht behoben.
Vielleicht kann mir das jemand erklären:
Wieso kann ich mit "Set xNodes = xDoc.lastChild.lastChild.lastChild.selectNodes("*")
                              Debug.Print xNodes.Item(0).Text"
mich zu dem gewünschten Knoten hangeln während
"Set xNodes = xDoc.selectSingleNode("//BkToCstmrDbtCdtNtfctn/Ntfctn/Id")
                              Debug.Print xNodes.Item(0).Text"
kein Ergebnis liefert. Egal wie ich es versuche, ich kann keinen Knoten adressieren ausser ich mache es wie oben beschrieben (.lastchild.firstchild.nextsibling.lastchild...).

Bopi

Hallo Zusammen

Ich habe mein Problem gelöst: Es lag an den Namespaces. Ich habe mir über Visual Studio eine Schema Datei erstellen lassen. Dabei habe ich gesehen, dass Namespaces verwendet werden. Also habe ich die Eigenschaft "SelectionNamespaces" ausgelesen und explicit gesetzt. Das sieht dann so aus:
xDoc.SetProperty "SelectionNamespaces", xDoc.getProperty("SelectionNamespaces")Das kann man dann als Text auseinander nehmen und so den Namespace bei der SelectNode(s) Abfrage einfügen. Also z.B.
xdoc.selectNodes("//MyNamespace:MyNode/*")Auch einen einzelnen Knoten kann man so ansteuern. Wenn man genau weiss wie der Namespace heisst, kann man ihn natürlich auch ohne SetProperty direkt einfügen.

Vielleicht hilft es mal jemandem.