如何在powershell中获取depth中的xml值

ecfdbz9o  于 2023-02-23  发布在  Shell
关注(0)|答案(1)|浏览(157)

我有下面的xml文件,有id和值。需要field_name =test2的结果,id为3

<Types>
<Type field_name="Test1">
    <items>
        <item>
            <id>1</id>
            <value>A</value>
        </item>
        <item>
            <id>2</id>
            <value>B</value>
        </item>
        <item>
            <id>3</id>
            <value>C</value>
        </item>
        <item>
            <id>4</id>
            <value>D</value>
        </item>
    </items>
    </Type>
    <Type field_name="Test2">
    <items>
        <item>
            <id>1</id>
            <value>A</value>
        </item>
        <item>
            <id>2</id>
            <value>B</value>
        </item>
        <item>
            <id>3</id>
            <value>C</value>
        </item>
        <item>
            <id>4</id>
            <value>D</value>
        </item>
    </items>
    </Type>
</Types>

我需要通过field_name =test2获得id的结果,我尝试了下面的代码,但没有成功。

$xml = [xml](Get-Content "C:\Test.xml")
$xml.types.type.items.item | ? {$_.id -eq 3} | select value
yftpprvb

yftpprvb1#

# This is a more robust way to load an XML file (PSv5+).
# In earlier versions, use ($xml = New-Object xml)...
($xml = [xml]::new()).Load((Convert-Path C:\Test.xml))

# PSv4+ syntax
@($xml.types.type.Where({ $_.'field_name' -eq 'Test2' }, 'First').
  items).ForEach({ $_.item }).Where({ $_.id -eq 3 }).value

请注意,PSv4 + .Where().ForEach()数组方法用于过滤和枚举,特别是需要使用.ForEach()显式枚举<item>子元素(参见下节)。
注意:严格地说,由于.Where()调用只返回一个 * single * 对象,该对象只有一个 * single * items子元素,因此.ForEach()在 * this * 情况下并不是严格必需的,但在原始代码中却是必需的。
另请注意@(...)的使用,这仅在 * Windows PowerShell * 中是必需的,因为 * PowerShell(Core)7 +* 中已修复了一个错误
但是,使用XPath查询更容易,它与Select-Xml结合使用,可实现单命令解决方案:

(Select-Xml '//Type[@field_name="Test2"]/items/item[id=3]' C:\Test.xml).Node.value

注:

  • 如果XML文档使用 * namespaces *,则必须将带有前缀到URIMap的哈希表传递给-Namespace参数,并在查询中引用元素时使用这些前缀-有关详细信息,请参见this answer
  • 相比之下,如果使用PowerShell的XML DOM适配(基于属性的访问),则元素名称中的名称空间声明和名称空间前缀将被 * 忽略 *。

至于你所尝试的
除了您的代码没有尝试按field_name="Test2"进行过滤(如果id值在整个文档中是唯一的,则可能不需要)之外,您的问题还在于对值为 * array * 的父属性.items使用了.item属性:

    • 因为.items是一个 * 数组 ,并且数组有一个 * type-native * .Item成员*[1],所以该成员优先于PowerShell's adaptation of the XML DOM(其中属性和子元素看起来 * 就像 * 它们是属性一样),所以**名为item的XML子元素不再可以通过.item**直接访问。
    • 通过.ForEach({ $_.item }) [2]显式枚举数组元素(在本例中是XML元素)可以绕过这个问题**,然后访问每个[XmlElement]上的.item属性就可以正常工作。

注意:XmlElements也有一个类型原生的.Item属性,但在PowerShell对XML DOM的适应上下文中,逻辑是 * 相反的 adapted * 属性优先于类型原生属性(后者可以作为带有get_前缀的 * methods * 访问;例如,.get_Index())-参见this answer,以获得一个修改后的.Name属性(来自子元素或属性)隐藏元素的类型原生属性的示例。
[1]从技术上讲,参数化的.Item属性是通过 * interface *(IList)公开的,但PowerShell将此类显式接口实现属性作为类型的直接属性公开。
[2]理想情况下,您可以使用.ForEach('item')作为更快的替代方案,但截至PowerShell(核心)7.2,由于GitHub issue #15994中详细介绍的一个 * bug *,这不起作用。

相关问题