英文:
Access XML data within a Powershell object
问题
我正在尝试从XML中读取数据到Powershell中。我想循环遍历所有Subbook元素。每个Subbook元素都包含一些variable元素,此外还包含其他我需要处理的元素。我可以设置循环。
[xml]$xmlfile = Get-Content -Path $xmlpath
$subbooks = Select-Xml -Path $xmlpath -XPath '//Subbook'
$subbooks | ForEach-Object {
$MDC = $_.Node.SelectNodes('variable[@Name="Metadata_Code"]/@Value')
}
但是然后我卡住了。我需要选择具有名称'Metadata_Code'的variable节点的值。在XSLT中,这是variable[@Name='Metadata_Code']/@Value。
$MDC保持为空。我如何将我需要的值放入这个变量中?
英文:
I'm trying to read data from an XML into Powershell.
<?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"/>
<Topic...>
<Topic....>
</Subbook>
<Subbook id="1849">
<variable Name="Metadata_Code" Value="B-"/>
<variable Name="Metadata_Installation" Value="pod - B"/>
<Topic...>
<Topic....>
</Subbook>
</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.
[xml]$xmlfile = Get-Content -Path $xmlpath
$subbooks = Select-Xml -Path $xmlpath -XPath '//Subbook'
$subbooks | ForEach-Object {
$MDC = $_.Node.SelectNodes('variable[@Name="Metadata_Code"]/@Value')
}
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来执行筛选,代码将如下所示:
($xmlfile = [xml]::new()).Load($xmlpath)
$xmlfile.Book.Subbook.variable |
Where-Object Name -EQ 'Metadata_Code' |
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:
($xmlfile = [xml]::new()).Load($xmlpath)
$xmlfile.Book.Subbook.variable |
Where-Object Name -EQ 'Metadata_Code' |
ForEach-Object Value
答案2
得分: 1
[Santiago的有益答案](https://stackoverflow.com/a/76432968/45375)向你展示了如何使用PowerShell的点符号适配`[xml]` DOM来解决你的问题。
至于你基于XPath的尝试:
根据[你自己的答案](https://stackoverflow.com/a/76433080/45375)进行了更新:
**简而言之**:**你的代码是有效的**,但一个**显示错误**阻止了你意识到这一点。详情如下。
- `$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),结果是**没有显示输出**。
- 虽然这应该被视为一个**错误** - 请参见[GitHub问题#19769](https://github.com/PowerShell/PowerShell/issues/19769) - 但使用`Write-Host`来显示**复杂对象**通常是没有帮助的。
- 实际上,[通常使用`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)。
- 此外 - 正如下面的代码中也显示的那样 - 你需要访问`$MDC`中`System.Xml.XmlAttribute`实例的`.Value`属性,以便只获取属性的**值**(文本)。
- 顺便说一句:如果你只是使用一个**标识属性**来查找**单个节点**,请使用[`.SelectSingleNode()`](https://learn.microsoft.com/en-US/dotnet/api/System.Xml.XmlDocument.SelectSingleNode)而不是`.SelectNodes()`
除此之外,你的代码可以**简化**。以下是一个包含你的样本XML的独立示例:
```powershell
# 创建样本XML文件
@'
<?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
# 让Select-Xml直接解析文件,并使用单个XPath查询提取目标节点。
Get-Item file.xml |
Select-Xml '//Subbook/variable[@Name="Metadata_Code"]/@Value' |
ForEach-Object { $_.Node.Value }
输出(在管道前面添加类似$MDC =
的内容以将输出字符串捕获到一个变量中):
A-
B-
<details>
<summary>英文:</summary>
<!-- language-all: sh -->
[Santiago's helpful answer](https://stackoverflow.com/a/76432968/45375) shows you how to solve your problem using [PowerShell's dot-notation-based adaptation of the `[xml]` DOM](https://stackoverflow.com/a/49213568/45375).
As for your **XPath-based** attempt:
_Update_, based on [your own answer](https://stackoverflow.com/a/76433080/45375):
**tl;dr**: **Your code *works***, but a **display bug** prevented you from realizing that. Details below.
* **`$MDC` wasn'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_.
* 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_.
* 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).
* 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's _value_ (text).
* As an aside: If you'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()`
Aside from that, your **code can be simplified**.
Here'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 }
Output (prepend something like `$MDC = ` to the pipeline above to capture the output strings in a variable):
```none
A-
B-
答案3
得分: 0
问题在于
$MDC = $_.Node.SelectNodes('variable[@Name="Metadata_Code"]/@Value')
输出一个节点集。我之前使用 Write-Host $MDC
来查看内容,但当变量内容是节点集时,这将显示为空。
这会给我所寻找的值:
$MDC = $_.Node.SelectNodes('variable[@Name="Metadata_Code"]/@Value').Value
英文:
The problem is that
$MDC = $_.Node.SelectNodes('variable[@Name="Metadata_Code"]/@Value')
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:
$MDC = $_.Node.SelectNodes('variable[@Name="Metadata_Code"]/@Value').Value
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论