【问题标题】:How can I rename an XML node using PowerShell?如何使用 PowerShell 重命名 XML 节点?
【发布时间】:2011-09-15 03:52:51
【问题描述】:

我正在尝试使用 PowerShell 重命名 XML 节点。例如:

<configuration>
<desktops>
   <name>PC001</name>
   <domain>CORP</domain>
</desktops>
<laptops>
   <name>PC002</name>
   <domain>CORP</domain>
</laptops>
</configuration>

我想将第一个 &lt;name&gt; 标签重命名为 &lt;PC1name&gt;(分别为 &lt;/PC1name&gt;)。到目前为止,这是我所拥有的:

$InputFile = "NetworkConfigs.xml"
$xml = [xml](get-content $InputFile)
$root = $xml.get_DocumentElement();
#replace the node
$root.desktops.name.?
  
$xml.Save($InputFile)

我不知道如何用其他东西替换&lt;name&gt; 标签。提示?

【问题讨论】:

    标签: xml powershell


    【解决方案1】:

    归根结底,XML 节点的名称是不可变的。参考msdn

    这是一个使用所需数据创建新节点的快速示例。希望能帮助到你。

    $InputText = @"
    <configuration>
    <desktops>
    <name>PC001</name>
    <domain>CORP</domain>
    </desktops>
    <laptops>
    <name>PC002</name>
    <domain>CORP</domain>
    </laptops>
    </configuration>
    "@
    
    $xml = [xml]($inputText)
    $desktopsNode = [System.Xml.XmlElement]$xml.configuration.desktops
    $nameNode = $desktopsNode.SelectSingleNode('name')
    $pcNameNode = $xml.CreateElement('PC1Name')
    $pcNameNode.InnerText = $nameNode.InnerText
    [void]$desktopsNode.AppendChild($pcNameNode)
    [void]$desktopsNode.RemoveChild($nameNode)
    $xml.OuterXML
    

    输出:

    <configuration><desktops><domain>CORP</domain><PC1Name>PC001</PC1Name></desktops><laptops><name>PC002</n
    ame><domain>CORP</domain></laptops></configuration>
    

    【讨论】:

    • 这很有效,我需要使用一个文件作为输入和输出。所以,我用$InputFile 替换了$InputText 并应用了使用$xml.OuterXML 显示的更改但是,我怎样才能保存XML 文件?我试过$xml.Save($InputFile) 但这不起作用。
    • 该错误应该告诉您保存时出了什么问题。文件是否被锁定?还是 $xml 对象没有 Save 方法? (如果是这种情况,您需要获取 System.Xml.XmlDocument 的句柄。)关键是仔细观察错误消息并查看相应的对象文档。
    【解决方案2】:

    在 XML 中重命名节点比您想象的要复杂。如果节点是根节点或具有复杂子节点层次结构的父节点,则尤其糟糕。我见过的大多数“重命名”方法都会克隆孩子并将它们附加到新节点。如果您的 API 还包含 ReplaceChild 方法,则此过程会更容易一些。 (如果您需要,我可以提供详细信息。)

    我使用的另一种方法(特别是如果 XML 可以表示为字符串)是在将 XML 转换为 XmlDocument 之前替换 XML 中的文本。

    $InputText = @"
    <configuration>
    <desktops>
    <name>PC001</name>
    <domain>CORP</domain>
    </desktops>
    <laptops>
    <name>PC002</name>
    <domain>CORP</domain>
    </laptops>
    </configuration>
    "@
    
    $regex = [regex]'(</?)name>'
    $ModifiedText = $regex.Replace($InputText,"`$1PC1Name>",2)
    $xml = [xml]$ModifiedText
    

    请注意,replace 语句查找并修复匹配的前 2 次匹配项——仅第一个元素的开始和结束标记。删除数字以查找并替换字符串中的所有匹配项。另请注意,正则表达式捕获开始标记字符,以便它们可以作为 $1 插入到字符串匹配中。

    【讨论】:

      【解决方案3】:
      $oldtag = "name"
      $newtag = "PC1name"
      $xml = Get-Content D:\oldfile.xml
      $new = $xml -replace $oldtag, $newtag
      Set-content -path D:\newfile.xml -value $new
      

      我的方法是将 XML 转换为字符串,然后替换节点(在这种情况下只是普通字符串)。 这个对我有用。

      【讨论】:

      • 非常糟糕的解决方案...如果您的字符串恰好出现在其他地方,那么您就犯了一个大错误
      【解决方案4】:

      simple C# solution 的启发,我最终得到了这个函数(它也处理属性):

      Function RenameXmlNode ($oldNode, $newName) {
          $newNode = $oldNode.OwnerDocument.CreateElement($newName)
      
          foreach ($childNode in $oldNode.ChildNodes) {
              $newNode.AppendChild($childNode.CloneNode($true))
          }
      
          foreach ($attribute in $oldNode.Attributes) {
              $newNode.Attributes.Append($attribute)
          }
      
          $parent = $oldNode.ParentNode
          $parent.ReplaceChild($newNode, $oldNode)
          return $newNode
      }
      

      如果不需要结果,可以忽略 - 重命名的节点已经是文档的一部分,$oldNode 属于。

      例子:

      $InputFile = "NetworkConfigs.xml"
      [xml] $doc = Get-Content $InputFile
      $nameNode = $doc.SelectSingleNode('/configuration/desktops/name')
      
      RenameXmlNode $nameNode $nameNode.InnerText  
      
      $xml.Save($InputFile)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-01-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多