Hallo Robert,
hier ist der Agent:
Declarations:
Dim domParser As NotesDOMParser
Dim LF As String
Dim db As NotesDatabase
Dim unsavedDoc As Integer
Dim doc As NotesDocument
Dim strCurrentNodeName As String
Initialize:
Sub Initialize
Dim session As NotesSession
Dim inputStream As NotesStream, outputStream As NotesStream
Dim docNode As NotesDOMDocumentNode
Dim origXML As String, outputFile As String
origXML = "c:\dxl\in.xml"
outputFile = "c:\dxl\DOMtree.txt"
unsavedDoc = False
Dim header As String
header = "Walk Tree agent"
LF = Chr(13)+Chr(10)
On Error Goto errh
Set session = New NotesSession
Set db = session.CurrentDatabase
'create the output file
Set outputStream =session.CreateStream
outputStream.Open (outputFile)
outputStream.Truncate
'write report title
outputStream.WriteText ("DOM Parser Report - " )
outputStream.WriteText (header+LF)
'open the XML file
Set inputStream = session.CreateStream
inputStream.Open (origXML)
If inputStream.Bytes = 0 Then
outputStream.WriteText (origXML+" is empty"+LF)
Goto results
End If
'create DOM parser and process
Set domParser=session.CreateDOMParser(inputStream, outputStream)
domParser.Process
'get the document node
Set docNode = domParser.Document
Call walkTree(docNode)
results:
Call outputStream.Close
Exit Sub
errh:
outputStream.WriteText ("errh: "+Cstr(Err)+": "+Error+LF)
Resume results
End Sub
Sub walkTree:
Sub walkTree ( node As notesdomnode)
Dim child As notesdomnode
Dim elt As notesdomnode
Dim attrs As notesdomnamednodemap
Dim a As notesdomattributenode
Dim piNode As Notesdomprocessinginstructionnode
LF = Chr(13)+Chr(10)
If Not node.IsNull Then
Select Case node.NodeType
Case DOMNODETYPE_DOCUMENT_NODE: ' If it is a Document node
domParser.Output( "Document node: "+node.Nodename )
Set child = node.FirstChild ' Get the first node
Dim numChildNodes As Integer
numChildNodes = node.NumberOfChildNodes
domParser.Output(" has "+Cstr(numChildNodes)+" Child Nodes"+LF)
While numChildNodes > 0
Set child = child.NextSibling ' Get next node
numChildNodes = numChildNodes - 1
Call walkTree(child)
Wend
Case DOMNODETYPE_DOCUMENTTYPE_NODE: ' It is a <!DOCTYPE> tag
domParser.Output("Document Type node: "+ node.NodeName+LF)
Case DOMNODETYPE_TEXT_NODE: ' Plain text node
domParser.Output("Text node: "+node.NodeValue+LF)
Dim strNodeValue As String
strNodeValue = node.nodeValue
If unsavedDoc Then
Stop
If Trim(node.NodeValue) <> "" And Uni(node.NodeValue) <> 10 And Uni(node.NodeValue) <> 13 Then ' hack -> ignore whitespace
Print Uni(node.NodeValue)
Call doc.ReplaceItemValue(strCurrentNodeName, node.NodeValue)
End If
If strCurrentNodeName = "Volume" Then ' hack! der letzte Tag
doc.Save True, False
unsavedDoc = False
End If
End If
Case DOMNODETYPE_ELEMENT_NODE: ' Most nodes are Elements
strCurrentNodeName = node.NodeName
'stop
domParser.Output("Element node: "+node.NodeName )
If (node.NodeName = "Row") Then
Stop
If unsavedDoc = False Then
'stop
Set doc= db.CreateDocument
doc.form = "row"
unsavedDoc = True
End If
Else
If unsavedDoc Then
strCurrentNodeName = node.NodeName
End If
End If
Set elt = node
numChildren = elt.NumberOfChildNodes
Set child = elt.FirstChild ' Get child
While numChildren > 0
Call walkTree(child)
Set child = child.NextSibling ' Get next child
numChildren = numChildren - 1
Wend
domParser.Output( elt.nodeName+LF)
Case DOMNODETYPE_COMMENT_NODE: ' Comments
domParser.Output("Comment node: "+node.NodeValue+LF)
Case DOMNODETYPE_PROCESSINGINSTRUCTION_NODE: ' Handle PI nodes
Set piNode = node
domParser.Output("Processing Instruction node: " )
domParser.Output(" with Target "+piNode.Target+_
" and Data "+piNode.Data+LF)
Case DOMNODETYPE_CDATASECTION_NODE: ' CDATA sections
domParser.Output("CDATA Section node: "+node.NodeName)
domParser.Output(" has value of "+node.NodeValue+LF)
Case DOMNODETYPE_ENTITYREFERENCE_NODE: ' Handle entities
domParser.Output("Entity Reference node: "+node.NodeName+LF)
Case Else:
domParser.Output("Ignoring node: "+Cstr(node.NodeType)+LF)
End Select 'node.NodeType
End If 'Not node.IsNull
End Sub
Die Datei (so aufgebaut wie von dir gepostet) wird von C:\dxl\in.xml gelesen. An diesen Ort und unter diesen Namen solltest du die zu parsende xml-Datei vor Start des Agenten speichern. Der Name ist wirklich irreführend, weil das mit dxl nix zu tun hat. Ausserdem generiert der Code noch eine Report-Datei. Nicht weil das irgendwie sinnvoll wäre. Ich hab ja den Anfang aus der Notes Hilfe und da war das dabei. Für den echten Agenten würd ichs auf jeden Fall aufbauen. Das ist hier nur so eine Art proof of concept.
Der Agent besitzt weitere Schwächen. Z.B. sollten die globalen Variablen Dim unsavedDoc As Integer, Dim doc As NotesDocument, Dim strCurrentNodeName As String nicht global sein.
Eigentlich benutzt werden nur
- Case DOMNODETYPE_TEXT_NODE:
- Case DOMNODETYPE_ELEMENT_NODE: und
- Case DOMNODETYPE_DOCUMENT_NODE: (als Einstiegspunkt)
Die restlichen Case in walkTree kannst du vermutlich einfach löschen (habs nicht ausprobiert).
Errorhandling fehlt. Ausserdem hängt der Agent von der Reihenfolge der Elemente ab. Er erwartet, das Volume als letztes Child Tag von Row vorkommt. Normalerweise nehm ich für so Auslese-Operationen einen Parser des Typs SAX. Ich halte das aber für Anfänger in XML APIs für ein bischen verwirrender.
Ansonsten ist das aber ein brauchbarer Ansatz. Einfach starten und schaun, welche Dokumente der Agent erzeugt. Form ist "row".
Wichtig fürs Verständnis ist, dass die Unterroutine walkTree() z.T. rekursiv, d.h. aus walkTree() selbst aufgerufen wird.
Probleme beim nachvollziehen kann auch die Datei in.xml machen. Sie sollte in UTF-8 enkodiert sein. In guten Text-Editoren wie z.B. Textpad kann man das encoding beim Speichern auswählen, d.h. ist z.B. in Textpad Bestandteil des Speichern/Speichern Unter Dialogs.
Ansonsten wird in Notes-Blogger Kreisen immer so gerne der Wert von Standards evoziert. XML in Kombination mit Parsern des Typs DOM und SAX sind Standards zum parsen von hierarchisch strukturierten Dateien. Kann man dann auch nutzen.
Gruß Axel