使用 PowerShell 解析带有命名空间的 XML [英] Parsing XML with namespace with PowerShell
问题描述
我需要一点帮助来理解 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>
(withoutsite-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)
}
几个问题:
使用此代码,我可以选择所需的产品节点.PowerShell 显示:
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:
用于选择没有特定属性的节点:
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屋!