Add child entry to a specific node in xml file in

2019-05-26 05:17发布

问题:

I have an xml file DataConfiguration.xml with this entry

<DataSource>
 <localdata>
    <add context="Localization">
       <parameter name="timeout" type="int" defaultvalue="60"/>
       <parameter name="address" type="string" defaultvalue="192.168.9.45" />
       <parameter name="port" type="int" defaultvalue="6789"/>
    </add>
</localdata>
</DataSource>

I need to add another entry to "localdata" so it would be

 <DataSource>
     <localdata>
        <add context="Localization">
           <parameter name="timeout" type="int" defaultvalue="60"/>
           <parameter name="address" type="string" defaultvalue="192.168.9.45" />
           <parameter name="port" type="int" defaultvalue="6789"/>
        </add>
       <add context="General">
           <parameter name="timeout" type="int" defaultvalue="60"/>
           <parameter name="address" type="string" defaultvalue="192.168.9.478" />
           <parameter name="port" type="int" defaultvalue="5674"/>
        </add>
    </localdata>
    </DataSource>

How would I add this in vbscript?

My Current code

'created xml file object
Set xmlDoc = CreateObject("Msxml2.DOMDocument")

xmlDoc.async = False  
xmlDoc.preserveWhiteSpace= True 
xmlDoc.load("DataConfiguration.xml")

Dim entry

entry = "<add context=""General"">" & _
               <parameter name=""timeout"" type=""int"" defaultvalue=""60""/>" & _ 
               <parameter name=""address"" type=""string"" defaultvalue=""192.168.9.478"" />" & _
               <parameter name=""port"" type=""int"" defaultvalue=""5674""/>"& _
            </add>"

Set NewNode = xmlDoc.createElement(entry)
Set ElemList = xmlDoc.getElementsByTagName("localdata")
ElemList.appendChild(NewNode)

But this give the error

This name may not contain < character" at " Set NewNode = xmlDoc.createElement(entry)

Also the ElemList.appendChild(NewNode) does not work.

回答1:

XmlDocument.CreateElement accepts three params: a node type, a node name, and a namespace. In your example, since your child element is named "add", it's an element (type==1), and it is part of the global xml namespace, you would call xmlDoc.CreateElement(1, "add", "") .

That gives you an empty element. To insert the data you want (the Context="General" attribute, and all the child elements), you'd then need to make successive calls to the DOM manipulation methods, to add in each child element, each attribute, and so on. Pretty laborious.

But you already have the xml fragment as a string. So instead of creating the element using DOM methods, what you can do is create a 2nd XmlDocument and tell it to get its content from the string. Then grab the documentElement from that 2nd doc. Then call appendChild on the appropriate node in first doc, passing the documentElement from the 2nd doc.

something like this:

Function GetElementFromXmlString(xmlString)
    Dim doc
    set doc = CreateObject("Msxml2.DOMDocument.6.0")
    doc.async = False
    doc.preserveWhiteSpace= False
    doc.loadXML(xmlString)
    Set GetElementFromXmlString = doc.documentElement
End Function

Sub Main()
    Set doc1 = CreateObject("Msxml2.DOMDocument.6.0")
    doc1.async = False
    doc1.preserveWhiteSpace= False ' True
    doc1.load("DataConfiguration.xml")

    ' generate an Element from an XML string
    Dim xmlString
    xmlString = "<add context=""General"">" & _
                  " <parameter name=""timeout"" type=""int"" defaultvalue=""60""/>" & _
                  " <parameter name=""address"" type=""string"" defaultvalue=""192.168.9.478"" />" & _
                  " <parameter name=""port"" type=""int"" defaultvalue=""5674""/>"& _
              "</add>"
    Dim newElt
    Set newElt = GetElementFromXmlString(xmlString)

    ' get the first child node of type=Element under the document root element in
    ' doc1.  This is not the same as  doc1.documentElement.firstChild.  There can
    ' be text nodes, etc.
    Dim node1
    Set node1 = doc1.documentElement.selectSingleNode("./*[position()=1]")

    ' append the element to the node
    node1.appendChild(newElt)

    WScript.echo (PrettyPrintXml (doc1))
End Sub

Main()

...where the PrettyPrintXml function is defined like this:

Function PrettyPrintXml(xmldoc)
    Dim reader
    set reader = CreateObject("Msxml2.SAXXMLReader.6.0")
    Dim writer
    set writer = CreateObject("Msxml2.MXXMLWriter.6.0")
    writer.indent = True
    writer.omitXMLDeclaration = True
    reader.contentHandler = writer
    reader.putProperty "http://xml.org/sax/properties/lexical-handler", writer
    reader.parse(xmldoc)
    PrettyPrintXml = writer.output
End Function

The output of this, for me, is:

<DataSource>
  <localdata>
    <add context="Localization">
      <parameter name="timeout" type="int" defaultvalue="60"/>
      <parameter name="address" type="string" defaultvalue="192.168.9.45"/>
      <parameter name="port" type="int" defaultvalue="6789"/>
    </add>
    <add context="General">
      <parameter name="timeout" type="int" defaultvalue="60"/>
      <parameter name="address" type="string" defaultvalue="192.168.9.478"/>
      <parameter name="port" type="int" defaultvalue="5674"/>
    </add>
  </localdata>
</DataSource>