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 |
| |
| |
| Set outputStream =session.CreateStream |
| outputStream.Open (outputFile) |
| outputStream.Truncate |
| |
| |
| outputStream.WriteText ("DOM Parser Report - " ) |
| outputStream.WriteText (header+LF) |
| |
| |
| Set inputStream = session.CreateStream |
| inputStream.Open (origXML) |
| If inputStream.Bytes = 0 Then |
| outputStream.WriteText (origXML+" is empty"+LF) |
| Goto results |
| End If |
| |
| |
| Set domParser=session.CreateDOMParser(inputStream, outputStream) |
| domParser.Process |
| |
| |
| 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