【问题标题】:adding XML sub-elements添加 XML 子元素
【发布时间】:2012-06-14 18:48:50
【问题描述】:

使用 PowerShell,我想将几​​个子元素添加到 XML 树中。
我知道添加一个元素,我知道添加一个或多个属性,但我不明白如何添加几个元素。

一种方式应该是write a sub-XML tree as text
但是我不能使用这种方法,因为元素不是一次添加的。

要添加一个元素,我会这样做:

[xml]$xml = get-content $nomfichier
$newEl = $xml.CreateElement('my_element')
[void]$xml.root.AppendChild($newEl)

工作正常。这给了我这个 XML 树:

$xml | fc
class XmlDocument
{
  root =
    class XmlElement
    {
      datas =
        class XmlElement
        {
          array1 =
            [
              value1
              value2
              value3
            ]
        }
      my_element =     <-- the element I just added
    }
}

现在我想向“my_element”添加一个子元素。我使用类似的方法:

$anotherEl = $xml.CreateElement('my_sub_element')
[void]$xml.root.my_element.AppendChild($anotherEl) <-- error because $xml.root.my_element is a string
[void]$newEl.AppendChild($anotherEl)               <-- ok
$again = $xml.CreateElement('another_one')
[void]$newEl.AppendChild($again)

这给出了这个 XML 树(部分显示):

my_element =
  class XmlElement
  {
    my_sub_element =
    another_one =
  }

这些是属性,而不是子元素。
子元素将显示为:

my_element =
  [
    my_sub_element
    another_one
  ]

问题:如何一次添加多个子元素?

【问题讨论】:

    标签: xml powershell


    【解决方案1】:

    看看下面的例子:

    # Document creation
    [xml]$xmlDoc = New-Object system.Xml.XmlDocument
    $xmlDoc.LoadXml("<?xml version=`"1.0`" encoding=`"utf-8`"?><Racine></Racine>")
    
    # Creation of a node and its text
    $xmlElt = $xmlDoc.CreateElement("Machine")
    $xmlText = $xmlDoc.CreateTextNode("Mach1")
    $xmlElt.AppendChild($xmlText)
    
    # Creation of a sub node
    $xmlSubElt = $xmlDoc.CreateElement("Adapters")
    $xmlSubText = $xmlDoc.CreateTextNode("Network")
    $xmlSubElt.AppendChild($xmlSubText)
    $xmlElt.AppendChild($xmlSubElt)
    
    # Creation of an attribute in the principal node
    $xmlAtt = $xmlDoc.CreateAttribute("IP")
    $xmlAtt.Value = "128.200.1.1"
    $xmlElt.Attributes.Append($xmlAtt)
    
    # Add the node to the document
    $xmlDoc.LastChild.AppendChild($xmlElt);
    
    # Store to a file 
    $xmlDoc.Save("c:\Temp\Temp\Fic.xml")
    

    编辑

    备注:Using a relative path in Save will not do what you expect.

    【讨论】:

    • 比我迄今为止发现的解决方案要好得多!而且更清洁。谢谢。
    • 这很好用。我的问题是,它在控制台上写了很多东西。调试显示它发生在这一行: $xmlSubElt.AppendChild($xmlSubText) 如果我将 "> $null" 写到最后。写了别的东西我可以阻止它吗?
    • | out-null替换&gt; $null
    • 要禁止向控制台输出,您也可以简单地在所有函数调用前加上[void],如下所示:[void]$xmlDoc.LoadXml(...)。赋值$var = something 不输出任何内容,但函数调用实际上会默认生成输出(它们的返回值)。
    【解决方案2】:

    我更喜欢手动创建 xml,而不是使用 API 逐个节点地构造它,因为恕我直言,手动创建它会更易读且更易于维护。

    这是一个例子:

    $pathToConfig = $env:windir + "\Microsoft.NET\Framework64\v4.0.30319\Config\web.config"
    
    $xml = [xml] (type $pathToConfig)
    
    [xml]$appSettingsXml = @"
    <appSettings>
        <add key="WebMachineIdentifier" value="$webIdentifier" />
    </appSettings>
    "@
    
    
    $xml.configuration.AppendChild($xml.ImportNode($appSettingsXml.appSettings, $true))
    $xml.Save($pathToConfig)
    

    【讨论】:

    • 写成函数(并且可能更好地处理命名空间?)gist.github.com/thoemmi/2937183
    • 如果 有命名空间,你知道怎么做吗?特别是 .
    • 注意"@ 需要在行首,不允许有空格。
    • 如果你要添加的节点是这样的,主名称包含点:&lt;foo.bar.hello.world&gt;&lt;settings value=42&gt;&lt;/foo.bar.hello.world&gt;,你需要在导入节点中写这样的变量:$xml.ImportNode($appSettingsXml.{foo.bar.hello.world}, $true))
    • 这对我不起作用。运行 echo $appSettingsXml 什么也不输出
    【解决方案3】:

    检查此代码示例。它拥有从头开始创建 XML 所需的一切:

    function addElement($e1, $name2, $value2, $attr2)
    {
        if ($e1.gettype().name -eq "XmlDocument") {$e2 = $e1.CreateElement($name2)}
        else {$e2 = $e1.ownerDocument.CreateElement($name2)}
        if ($attr2) {$e2.setAttribute($value2,$attr2)}
        elseif ($value2) {$e2.InnerText = "$value2"}
        return $e1.AppendChild($e2)
    }
    
    function formatXML([xml]$xml)
    {
        $sb = New-Object System.Text.StringBuilder
        $sw = New-Object System.IO.StringWriter($sb)
        $wr = New-Object System.Xml.XmlTextWriter($sw)
        $wr.Formatting = [System.Xml.Formatting]::Indented
        $xml.Save($wr)
        return $sb.ToString()
    }
    

    ...现在让我们使用这两个函数来创建和显示一个新的 XML 对象:

    $xml = New-Object system.Xml.XmlDocument
    $xml1 = addElement $xml "a"
    $xml2 = addElement $xml1 "b"
    $xml3 = addElement $xml2 "c" "value"
    $xml3 = addElement $xml2 "d" "attrib" "attrib_value"
    
    write-host `nFormatted XML:`r`n`n(formatXML $xml.OuterXml)
    

    结果如下所示:

    Formatted XML:
    
     <?xml version="1.0" encoding="utf-16"?>
    <a>
      <b>
        <c>value</c>
        <d attrib="attrib_value" />
      </b>
    </a>
    

    【讨论】:

      【解决方案4】:

      对于其他访问此的人。

      我遇到了问题,因为我的父文档有一个命名空间,而 ImportNode 正在向导入的 xml 添加一个空的 xmnls="" 元素,导致我的应用出现问题

      扩展上面的答案。 为了解决这个问题,将其包装在一个虚拟节点中,并从父文档中设置命名空间

      $pathToConfig = $env:windir + "\Microsoft.NET\Framework64\v4.0.30319\Config\web.config"
      
      $xml = [xml] (type $pathToConfig)
      $root = $xml.get_DocumentElement()
      $namespaceuri = $root.NamespaceURI
      
      [xml]$appSettingsXml = @"
      <Dummy xmlns="$namespaceuri">
          <appSettings>
              <add key="WebMachineIdentifier" value="$webIdentifier" />
          </appSettings>
      </Dummy>
      "@
      
      
      $xml.configuration.AppendChild($xml.ImportNode($appSettingsXml.Dummy.appSettings, $true))
      $xml.Save($pathToConfig)
      

      【讨论】:

        猜你喜欢
        • 2018-12-07
        • 2013-07-19
        • 1970-01-01
        • 1970-01-01
        • 2017-10-22
        • 2020-11-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多