访问 Powershell 对象中的 XML 数据

huangapple go评论89阅读模式
英文:

Access XML data within a Powershell object

问题

我正在尝试从XML中读取数据到Powershell中。我想循环遍历所有Subbook元素。每个Subbook元素都包含一些variable元素,此外还包含其他我需要处理的元素。我可以设置循环。

  1. [xml]$xmlfile = Get-Content -Path $xmlpath
  2. $subbooks = Select-Xml -Path $xmlpath -XPath '//Subbook'
  3. $subbooks | ForEach-Object {
  4. $MDC = $_.Node.SelectNodes('variable[@Name="Metadata_Code"]/@Value')
  5. }

但是然后我卡住了。我需要选择具有名称'Metadata_Code'的variable节点的值。在XSLT中,这是variable[@Name='Metadata_Code']/@Value。

$MDC保持为空。我如何将我需要的值放入这个变量中?

英文:

I'm trying to read data from an XML into Powershell.

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <?xml-stylesheet type="text/xsl" href="tmp.xslt"?>
  3. <Book>
  4. <Subbook id="1848">
  5. <variable Name="Metadata_Code" Value="A-"/>
  6. <variable Name="Metadata_Installation" Value="pod - A"/>
  7. <Topic...>
  8. <Topic....>
  9. </Subbook>
  10. <Subbook id="1849">
  11. <variable Name="Metadata_Code" Value="B-"/>
  12. <variable Name="Metadata_Installation" Value="pod - B"/>
  13. <Topic...>
  14. <Topic....>
  15. </Subbook>
  16. </Book>

I want to loop through all Subbook elements. Each Subbook element contains a few variable elements. In addition it contains other elements I have to process.
I can set up the loop.

  1. [xml]$xmlfile = Get-Content -Path $xmlpath
  2. $subbooks = Select-Xml -Path $xmlpath -XPath '//Subbook'
  3. $subbooks | ForEach-Object {
  4. $MDC = $_.Node.SelectNodes('variable[@Name="Metadata_Code"]/@Value')
  5. }

But then I'm stuck. I need to select the value of the variable node that has name 'Metadata_Code'. In XSLT this is variable[@Name='Metadata_Code']/@Value

$MDC remains empty. How can I get the value I need into this variable?

答案1

得分: 1

假设你在示例XML中正在寻找的是A-B-,如果你想要使用PowerShell来执行筛选,代码将如下所示:

  1. ($xmlfile = [xml]::new()).Load($xmlpath)
  2. $xmlfile.Book.Subbook.variable |
  3. Where-Object Name -EQ 'Metadata_Code' |
  4. ForEach-Object Value
英文:

Assuming what you're looking for in your example XML is A- and B-, if you want to use PowerShell to perform the filtering, the code would look like this:

  1. ($xmlfile = [xml]::new()).Load($xmlpath)
  2. $xmlfile.Book.Subbook.variable |
  3. Where-Object Name -EQ 'Metadata_Code' |
  4. ForEach-Object Value

答案2

得分: 1

  1. [Santiago的有益答案](https://stackoverflow.com/a/76432968/45375)向你展示了如何使用PowerShell的点符号适配`[xml]` DOM来解决你的问题。
  2. 至于你基于XPath的尝试:
  3. 根据[你自己的答案](https://stackoverflow.com/a/76433080/45375)进行了更新:
  4. **简而言之**:**你的代码是有效的**,但一个**显示错误**阻止了你意识到这一点。详情如下。
  5. - `$MDC`实际上**并不是空的**,但是你试图通过[`System.Xml.XmlNodeList`](https://learn.microsoft.com/en-US/dotnet/api/System.Xml.XmlNodeList)实例来进行可视化(由[`.SelectNodes()`](https://learn.microsoft.com/en-US/dotnet/api/System.Xml.XmlDocument.SelectNodes)返回),也就是通过[`Write-Host`](https://learn.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Utility/Write-Host),结果是**没有显示输出**。
  6. - 虽然这应该被视为一个**错误** - 请参见[GitHub问题#19769](https://github.com/PowerShell/PowerShell/issues/19769) - 但使用`Write-Host`来显示**复杂对象**通常是没有帮助的。
  7. - 实际上,[通常使用`Write-Host`是错误的工具](http://www.jsnover.com/blog/2013/12/07/write-host-considered-harmful/),除非意图是仅仅写入**显示**,绕过成功输出流,以及将输出发送到其他命令,将其捕获到一个变量中,或者将其重定向到文件中的能力。要输出一个值,请使用它**单独**,例如`$MDC`,而不是`Write-Host $MDC`(或使用`Write-Output $MDC`);参见[这个答案](https://stackoverflow.com/a/60534138/45375)。要明确地仅仅打印到显示器**但具有丰富的格式**,请使用[`Out-Host`](https://learn.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Core/Out-Host)。
  8. - 此外 - 正如下面的代码中也显示的那样 - 你需要访问`$MDC``System.Xml.XmlAttribute`实例的`.Value`属性,以便只获取属性的**值**(文本)。
  9. - 顺便说一句:如果你只是使用一个**标识属性**来查找**单个节点**,请使用[`.SelectSingleNode()`](https://learn.microsoft.com/en-US/dotnet/api/System.Xml.XmlDocument.SelectSingleNode)而不是`.SelectNodes()`
  10. 除此之外,你的代码可以**简化**。以下是一个包含你的样本XML的独立示例:
  11. ```powershell
  12. # 创建样本XML文件
  13. @'
  14. <?xml version="1.0" encoding="UTF-8"?>
  15. <?xml-stylesheet type="text/xsl" href="tmp.xslt"?>
  16. <Book>
  17. <Subbook id="1848">
  18. <variable Name="Metadata_Code" Value="A-"/>
  19. <variable Name="Metadata_Installation" Value="pod - A"/>
  20. </Subbook>
  21. <Subbook id="1849">
  22. <variable Name="Metadata_Code" Value="B-"/>
  23. <variable Name="Metadata_Installation" Value="pod - B"/>
  24. </Subbook>
  25. </Book>
  26. '@ > file.xml
  27. # 让Select-Xml直接解析文件,并使用单个XPath查询提取目标节点。
  28. Get-Item file.xml |
  29. Select-Xml '//Subbook/variable[@Name="Metadata_Code"]/@Value' |
  30. ForEach-Object { $_.Node.Value }

输出(在管道前面添加类似$MDC = 的内容以将输出字符串捕获到一个变量中):

  1. A-
  2. B-
  1. <details>
  2. <summary>英文:</summary>
  3. &lt;!-- language-all: sh --&gt;
  4. [Santiago&#39;s helpful answer](https://stackoverflow.com/a/76432968/45375) shows you how to solve your problem using [PowerShell&#39;s dot-notation-based adaptation of the `[xml]` DOM](https://stackoverflow.com/a/49213568/45375).
  5. As for your **XPath-based** attempt:
  6. _Update_, based on [your own answer](https://stackoverflow.com/a/76433080/45375):
  7. **tl;dr**: **Your code *works***, but a **display bug** prevented you from realizing that. Details below.
  8. * **`$MDC` wasn&#39;t actually _empty_**, but the way you tried to _visualize_ the [`System.Xml.XmlNodeList`](https://learn.microsoft.com/en-US/dotnet/api/System.Xml.XmlNodeList) instance it contained (returned by [`.SelectNodes()`](https://learn.microsoft.com/en-US/dotnet/api/System.Xml.XmlDocument.SelectNodes)), namely via [`Write-Host`](https://learn.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Utility/Write-Host) resulted in _no display output_.
  9. * While this should be considered a _bug_ - see [GitHub issue #19769](https://github.com/PowerShell/PowerShell/issues/19769) - it is rarely helpful to use `Write-Host` to display _complex objects_.
  10. * In fact, [`Write-Host` is typically the wrong tool to use](http://www.jsnover.com/blog/2013/12/07/write-host-considered-harmful/), unless the intent is to write _to the display only_, bypassing the success output stream and with it the ability to send output to other commands, capture it in a variable, or redirect it to a file. To output a value, use it _by itself_; e.g, `$MDC`, instead of `Write-Host $MDC` (or use `Write-Output $MDC`); see [this answer](https://stackoverflow.com/a/60534138/45375). To explicitly print only to the display _but with rich formatting_, use [`Out-Host`](https://learn.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Core/Out-Host).
  11. * Additionally - as also shown in the code below - you needed to access the `.Value` property of the instance [`System.Xml.XmlAttribute`](https://learn.microsoft.com/en-US/dotnet/api/System.Xml.XmlAttribute) in `$MDC` in order to get only the attribute&#39;s _value_ (text).
  12. * As an aside: If you&#39;re looking for just a _single_ node using an _identifying attribute_, use [`.SelectSingleNode()`](https://learn.microsoft.com/en-US/dotnet/api/System.Xml.XmlDocument.SelectSingleNode) instead of `.SelectNodes()`
  13. Aside from that, your **code can be simplified**.
  14. Here&#39;s a self-contained example with your sample XML:

Create sample XML file

@'
<?xml version="1.0" encoding="UTF-8"?>

<?xml-stylesheet type="text/xsl" href="tmp.xslt"?>
<Book>
<Subbook id="1848">
<variable Name="Metadata_Code" Value="A-"/>
<variable Name="Metadata_Installation" Value="pod - A"/>
</Subbook>
<Subbook id="1849">
<variable Name="Metadata_Code" Value="B-"/>
<variable Name="Metadata_Installation" Value="pod - B"/>
</Subbook>
</Book>
'@ > file.xml

Let Select-Xml parse the file directly

and use a single XPath query to extract the target nodes.

Get-Item file.xml |
Select-Xml '//Subbook/variable[@Name="Metadata_Code"]/@Value' |
ForEach-Object { $_.Node.Value }

  1. Output (prepend something like `$MDC = ` to the pipeline above to capture the output strings in a variable):
  2. ```none
  3. A-
  4. B-

答案3

得分: 0

问题在于

  1. $MDC = $_.Node.SelectNodes('variable[@Name="Metadata_Code"]/@Value')

输出一个节点集。我之前使用 Write-Host $MDC 来查看内容,但当变量内容是节点集时,这将显示为空。

这会给我所寻找的值:

  1. $MDC = $_.Node.SelectNodes('variable[@Name="Metadata_Code"]/@Value').Value
英文:

The problem is that

  1. $MDC = $_.Node.SelectNodes(&#39;variable[@Name=&quot;Metadata_Code&quot;]/@Value&#39;)

outputs a node-set.
I was using Write-Host $MDC to see the contents, this displays nothing when the variable content is a nodeset.

This gives me the value I was looking for:

  1. $MDC = $_.Node.SelectNodes(&#39;variable[@Name=&quot;Metadata_Code&quot;]/@Value&#39;).Value

huangapple
  • 本文由 发表于 2023年6月8日 22:15:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76432787.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定