繁体   English   中英

powershell xml排序节点和替换子节点

[英]powershell xml sort nodes and replacechild

我试着用powershell和xml做一些非常简单的事情,但没有一点麻烦。 基本上我正在尝试使用以下xml ...并按名称对机器元素进行排序。 然后将它们放回XML中,以便我可以保存回文件。

如果输出$ new对象,排序似乎有效,但是在替换它期间它抱怨“无法转换参数”0“,值为:”System.Object []“for”ReplaceChild“键入”System.Xml.XmlNode“: “无法将”System.Object []“转换为”System.Xml.XmlNode“类型。

如果我在$ orig和$ new上都有一个Get-Member,他们都说它们是XMLElement类型,我认为它继承自XMLNode。

我想念的是什么人? 使我抓狂。 谢谢你的帮助!

<company>
    <stuff>
    </stuff>
    <machines>
        <machine>
            <name>ca</name>
            <b>123</b>
            <c>123</c>
        </machine>
        <machine>
            <name>ad</name>
            <b>234</b>
            <c>234</c>
        </machine>
        <machine>
            <name>be</name>
            <b>345</b>
            <c>345</c>
        </machine>
    </machines>
    <otherstuff>
    </otherstuff>
</company>

[xml]$xml = (get-content Company.xml)
[XmlNode]$orig = $xml.Company.Machines
[XmlNode]$new = ($orig.Machine | sort Name )
$xml.Company.ReplaceChild($new, $orig)

这里有各种各样的问题。 一个是你的sort返回一个xml元素列表而不是一个xml元素。 另一个问题是它返回原始的xml元素而不是副本,因此使用它们对xml DOM的任何操作也会影响结果。

这是获得您想要的简单方法。 相反顺序排序,然后依次将每个节点插入其他节点前面。 每次从排序结果中插入节点时,它都会自动将其从原始节点集中删除:

[xml]$xml = @"
<company>
    <stuff>
    </stuff>
    <machines>
        <machine>
            <name>ca</name>
            <b>123</b>
            <c>123</c>
        </machine>
        <machine>
            <name>ad</name>
            <b>234</b>
            <c>234</c>
        </machine>
        <machine>
            <name>be</name>
            <b>345</b>
            <c>345</c>
        </machine>
    </machines>
    <otherstuff>
    </otherstuff>
</company>
"@
[System.Xml.XmlNode]$orig = $xml.Company.Machines
$orig.Machine | sort Name  -Descending |
  foreach { [void]$xml.company.machines.PrependChild($_) }
$xml.company.machines.machine

编辑:管道也可以按升序编写(如David Martin指出的那样),并且您可以通过使用变量中的节点来减少键入:

$orig.Machine | sort Name | % { [void]$orig.AppendChild($_) }

除了Duncan和robert.westerlund已经很出色的答案之外,我还想提供一个如何在节点不总是在同一路径中的情况下对xml元素进行排序的示例:

[xml]$xml = @"
<config>
    <namespace name='Some namespace'>
        <settings>
            <setting name='c setting' />
            <setting name='a setting' />
            <setting name='b setting' />
        </settings>
        <namespace name='Child namespace'>
            <settings>
                <setting name='z setting' />
                <setting name='y setting' />
                <setting name='x setting' />
            </settings>
        </namespace>
    </namespace>
</config>
"@

#[xml]$xml = Get-Content "PATH_TO_SOME_FILE.xml"

$xml.SelectNodes("//namespace/settings") | % { 
    $parentNode = $_; $_.Setting | Sort-Object -Property name | % { 
        $parentNode.AppendChild($_) | Out-Null
    } 
}

$xml.Save("PATH_TO_SOME_FILE.xml")

在此示例中, settings节点显示在xml文件中的不同级别上,并且已针对此级别进行排序。

这不起作用的原因是$ xml.Company.Machines是一个XmlElement。 要获取机器元素的集合,您需要使用$ xml.Company.Machines.Machine,因此这是您要排序的那个。

但是,ReplaceChild方法不会占用集合,所以我猜你必须删除所有子节点,然后按照你想要的顺序将它们追加。 像下面这样的东西应该工作正常:

[xml]$xml = Get-Content .\Company.xml
$machines = $xml.company.machines
$orderedMachineCollection = $machines.machine | Sort Name
$machines.RemoveAll()
$orderedMachineCollection | foreach { $machines.AppendChild($_) } | Out-Null

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM