使用 PowerShell 解析带有命名空间的 XML [英] Parsing XML with namespace with PowerShell

查看:43
本文介绍了使用 PowerShell 解析带有命名空间的 XML的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要一点帮助来理解 PowerShell 中的 XML.我有几个这样的 XML 文件:

I need a little help with understanding of an XML in PowerShell. I have several XML files like this:

<?xml version="1.0" encoding="UTF-8"?>
<catalog xmlns="http://www.example.com/xml/catalog/2006-10-31">
    <product product-id="11210">
        ...
        <available-flag>true</available-flag>
        <online-flag>false</online-flag>
        <online-flag site-id="ru">true</online-flag>
        <online-flag site-id="fr">true</online-flag>
        <online-flag site-id="uk">false</online-flag>
        <online-flag site-id="de">true</online-flag>
        ...
    </product>
    <product product-id="50610">
        ...
        <available-flag>true</available-flag>
        <online-flag>true</online-flag>
        <online-flag site-id="ru">false</online-flag>
        <online-flag site-id="fr">true</online-flag>
        <online-flag site-id="uk">false</online-flag>
        <online-flag site-id="de">fasle</online-flag>
        ...
    </product>
    <product product-id="82929">
        ...
        <available-flag>true</available-flag>
        <online-flag>true</online-flag>
        <online-flag site-id="ru">false</online-flag>
        <online-flag site-id="fr">true</online-flag>
        <online-flag site-id="uk">false</online-flag>
        <online-flag site-id="de">true</online-flag>
        ...
    </product>
</catalog>

我需要在 PowerShell 中获取两个元素的值:

I need to get the values of two elements in PowerShell:

  • (没有 site-id 属性)
  • <online-flag> (without site-id attribute)
  • <online-flag site-id="ru">

对于带有 product-id="50610" 的产品.

我有以下代码:

$Path = "C:\Temp\0\2017-08-12_190211.xml"
$XPath = "/ns:catalog/ns:product[@product-id='50610']"

$files = Get-ChildItem $Path | Where {-not $_.PSIsContainer}

if ($files -eq $null) {
    return
}

foreach ($file in $files) {
    [xml]$xml = Get-Content $file
    $namespace = $xml.DocumentElement.NamespaceURI
    $ns = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
    $ns.AddNamespace("ns", $namespace)
    $product = $xml.SelectSingleNode($XPath, $ns)
}

几个问题:

  1. 使用此代码,我可以选择所需的产品节点.PowerShell 显示:

  1. With this code I am able to select the needed product node. PowerShell shows:

online-flag        : {true, online-flag, online-flag, online-flag...}

但是我如何选择所需的 online-flag 元素的值(如果两种方式都可能:XPath 一种和对象一种)?

But how then I can select the values of the needed online-flag elements (if it is possible both ways: XPath one and the object one)?

是否可以以对象"方式选择节点?像这样:

Is it possible to select a node in the "object" way? Like this:

$product = $xml.catalog.product |
           Where-Object {$_."product-id".value -eq "50610"}

  • 如果我有多个文件,选择文件名、全局在线标志(无属性)、特定在线标志的最佳方法是什么?

  • If I have several files, what is the best way to select filename, global online-flag (without attributes), specific online-flag?

    推荐答案

    使用两种不同的 XPath 表达式:

    Use two different XPath expressions:

    1. 用于选择没有特定属性的节点:

    1. for selecting a node without a particular attribute:

    //ns:product[@product-id='50610']/ns:online-flag[not(@site-id)]
    

  • 用于选择具有特定属性值的节点:

  • for selecting a node with a particular attribute value:

    //ns:product[@product-id='50610']/ns:online-flag[@site-id='ru']
    

  • 您可以通过使 XPath 表达式相对于当前节点 (.) 来选择相对于已选择节点的节点:

    You can select nodes relative to an already selected node by making the XPath expression relative to the current node (.):

    $XPath = "/ns:catalog/ns:product[@product-id='50610']"
    ...
    $product = $xml.SelectSingleNode($XPath, $ns)
    $product.SelectSingleNode("./ns:online-flag[not(@site-id)]", $ns)
    $product.SelectSingleNode("./ns:online-flag[@site-id='ru']", $ns)
    

    如果您需要由文件名和两个节点值组成的结果数据,我建议您构建自定义对象:

    If you need result data consisting of the filename and the two node values I'd recommend building custom objects:

    $files | ForEach-Object {
        [xml]$xml = Get-Content $_
        ...
        New-Object -Type PSObject -Property @{
            'Filename'  = $_
            'online'    = $product.SelectSingleNode("./ns:online-flag[not(@site-id)]", $ns).'#text'
            'ru_online' = $product.SelectSingleNode("./ns:online-flag[@site-id='ru']", $ns).'#text'
        }
    }
    

    通过 Where-Object 使用点符号和过滤应该是可能的,但我不推荐它.我发现 XPath 效率更高.

    Using dot-notation and filtering via Where-Object should be possible, but I wouldn't recommend it. I find XPath far more efficient.

    这篇关于使用 PowerShell 解析带有命名空间的 XML的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆