XPathNodeList中的SelectNodes

时间:2016-04-04 10:33:18

标签: powershell xpath

给定一个像这样的

派生的XPathNodeList
$settingsNodes = $temp.xml.SelectNodes('/Settings/*')

给定一个特定的节点名称或ID,我可以迭代XPathNodeList,测试匹配并增加一个计数器。但是,我想知道是否有更优雅的东西,

$count = $settingsNodes.SelectNodes("//$nodeName")

这不起作用,因为XPathNodeList没有SelectNodes方法,我似乎无法找到任何有用的东西。谷歌搜索XPathNodeList SelectNodes返回对SelectNodes的所有种类的引用作为XmlNode的方法,但在XPathNodeList上没有任何内容。 我的具体情况意味着我几乎肯定永远不会循环超过几百到几千个节点,所以也许它真的没关系,它似乎有可能或更优雅的解决方案,我只是没有找到它

编辑:有关其他背景信息。

在一种情况下,我可能有这个XML,我只想捕获并记录重复的UserLogFilePath节点。

<Settings>
    <JobsXML>[Px~Folder]\Resources\jobs.xml</JobsXML>
    <JobLogFilePath>[Px~Folder]\Logs</JobLogFilePath>
    <JobLogFileName>[Px~StartTime] Job [Px~Job][Px~Error]</JobLogFileName>
    <MachineLogFilePath>[Px~Folder]\Logs</MachineLogFilePath>
    <MachineLogFileName>[Px~Now] [Px~Action] [Px~Set] on [Px~Computer][Px~Error][Px~Validation]</MachineLogFileName>
    <ResetLogFilePath>[Px~Folder]\Logs</ResetLogFilePath>
    <ResetLogFileName>[Px~Now] [Px~Action] on [Px~Computer][Px~Error][Px~Validation]</ResetLogFileName>
    <UserLogFilePath>[Px~Folder]\Logs</UserLogFilePath>
    <UserLogFilePath>C:\Program Files</UserLogFilePath>
    <UserLogFileName>[Px~User] on [Px~Computer]</UserLogFileName>
    <UserContextMember></UserContextMember>
    <UserContextNotMember>Administrators</UserContextNotMember>
</Settings>

如果没有重复项,整个Settings节点将导入到内存中的XML变量中。 稍后,我可能有这个XML,我想在任何Product_Group内外捕获重复的ID。

<Definitions>
    <Products>
        <Product_Group id="Miscellaneous">
            <Product id="ADSK360">
                <DefaultShortcut>Autodesk 360.lnk</DefaultShortcut>
                <ProgramDataFolder>C:\ProgramData\Autodesk\Autodesk ReCap</ProgramDataFolder>
                <ProgramFolder>C:\Program Files\Autodesk\Autodesk Sync</ProgramFolder>
                <ShortcutPath>C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Autodesk</ShortcutPath>
            </Product>
            <Product id="ADSK360">
                <DefaultShortcut>Autodesk 360.lnk</DefaultShortcut>
                <ProgramDataFolder>C:\ProgramData\Autodesk\Autodesk ReCap</ProgramDataFolder>
                <ProgramFolder>C:\Program Files\Autodesk\Autodesk Sync</ProgramFolder>
                <ShortcutPath>C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Autodesk</ShortcutPath>
            </Product>
        </Product_Group>
        <Product id="ADSK360">
            <DefaultShortcut>Autodesk 360.lnk</DefaultShortcut>
            <ProgramDataFolder>C:\ProgramData\Autodesk\Autodesk ReCap</ProgramDataFolder>
            <ProgramFolder>C:\Program Files\Autodesk\Autodesk Sync</ProgramFolder>
            <ShortcutPath>C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Autodesk</ShortcutPath>
        </Product>
    </Products>
</Definitions>

如果没有重复项,则会消除Product_Groups(这只是管理XML的用户的便利),并且所有产品都会导入到内存中的Products节点中。 首先检查后续产品文件是否为内部重复项,如果没有找到,则检查主XML中已有的重复项,如果没有找到,则合并文件的XML。在某些情况下,这可能会重复一百个或更多的文件。

基于当前循环的方法不够优雅,特别是对于内部重复测试。我在候选XML中创建一个XPathNodesList,比如说所有的Products。这是SelectNodes很好的地方,因为它可以在Product_Group中找到产品。然后我遍历每个产品并针对整个XPathNodesList进行测试。丑陋,因为只有10个节点的列表意味着循环100次。在针对最终XML测试候选时,它更有效,但仍然很难看。

编辑#2:编辑#2: 尝试使用Select,我正确地找到了重复的节点。

$settingsNodes = $temp.xml.SelectNodes('/Settings/*')
Write-Host "$($settingsNodes.count)"
Write-Host "$(($settingsNodes | select -unique).count)"

但是如何才能找到重复的ID?更好但重复具有相同节点名称的ID?由于不同的节点名称但相同的ID实际上不是重复的。 -unique是我看到的bool,所以我的猜测是我要学习更多关于流水线的知识,因为我需要提取ID来管道选择-unique,而不是Where-Object。在这种情况下,如何只提取ID?

好的,肠道测试在这里。我想也许我想要有点过于聪明,实际上有一个更简单的解决方案。就是......

$settingsNodes = $temp.xml.SelectNodes('/Settings/*')
$unique = $duplicate = @()
foreach ($node in $settingsNodes) {
    if ($unique -contains $node.Name) {
        $duplicate += $node.Name
    } else {
        $unique += $node.Name
    }
}
Write-Host "u: $unique"
Write-Host " "
Write-Host "d: $duplicate"

交换ID的名称,它也适用于此。 SelectNodes将负责消除Product_Group。同样,我可以在Final中构建一个节点数组,以测试现在唯一的候选节点列表。 所以,我错过了会咬我的东西吗?或者我应该继续踢自己? ;)

0 个答案:

没有答案