如何在powershell中获取深度深度xml值 [英] How to get depth in depth xml value in powershell

查看:23
本文介绍了如何在powershell中获取深度深度xml值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下 xml 文件,有 id 和 value .需要 ID 为 3 的 field_name =test2 的结果

I have below xml file , have id and value . Need result of field_name =test2 with 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>

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

I needs to get result by id with field_name =test2 , I had tried below code but no luck.

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

推荐答案

# 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() 用于过滤和枚举的数组方法,特别是需要显式枚举code> 带有 .ForEach() 的子元素(见底部).

Note the use of the PSv4+ .Where() and .ForEach() array methods for filtering and enumeration, and, specifically, the need to explicitly enumerate the <item> child elements with .ForEach() (see bottom section).

注意:严格来说,由于 .Where() 调用只返回一个 single 对象,该对象只有一个 single items 子元素,.ForEach()这种 情况下不是绝对必要的,但在您的原始代码中是.
还要注意 @(...) 的使用,它只在 Windows PowerShell 中是必需的,因为 PowerShell (Core) 7+

Note: Strictly speaking, since the .Where() call only returns a single object that has only a single items child element, the .ForEach() isn't strictly necessary in this case, but in your original code it is.
Also note the use of @(...), which is only necessary in Windows PowerShell, due to a bug that has since been fixed in PowerShell (Core) 7+

但是,使用XPath 查询更容易,其中,结合 Select-Xml,启用单命令解决方案:

However, it's easier to use an XPath query, which, in combination with Select-Xml, enables a single-command solution:

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

注意:

  • 如果您的 XML 文档使用命名空间,则必须将带有前缀到 URI 映射的哈希表传递给 -Namespace 参数,并在引用元素时的查询 - 请参阅此答案了解更多信息.

  • If your XML document uses namespaces, you must pass a hashtable with prefix-to-URI mappings to the -Namespace parameter, and use these prefixes in the query when referring to elements - see this answer for more information.

相比之下,如果您使用 PowerShell 的 XML DOM 适配(基于属性的访问),元素名称中的命名空间声明和命名空间前缀将被忽略.

By contrast, if you use PowerShell's XML DOM adaption (property-based access), namespace declarations and namespace prefixes in element names are ignored.

至于你尝试了什么:

除了您的代码不尝试通过 field_name="Test2" 过滤(如果 id 值在整个文档中是唯一的,则可能没有必要),您的问题是在 array 值的父属性 .items 上使用了 .item 属性:

Apart from your code not trying to filter by field_name="Test2" (which may not be necessary if the id values are unique across the entire document), your problem was the use of the .item property on the array-valued parent property, .items:

因为 .items 是一个 数组 并且数组有一个 type-native .Item 成员[1],该成员优先于 PowerShell 对 XML DOM 的改编(其中属性和子元素出现就好像它们是属性),因此名为 item 的子 XML 元素不再可以通过 .item.

Because .items is an array and arrays have a type-native .Item member[1], that member takes precedence over PowerShell's adaptation of the XML DOM (where attributes and child elements appear as if they were properties), so that the child XML elements named item are no longer directly accessible with .item.

数组元素(在本例中为 XML 元素)的显式枚举 - 通过 .ForEach({ $_.item })[2] - 绕过问题,并访问每个 [XmlElement] 然后按预期工作.

Explicit enumeration of the array elements (which are XML elements in this case) - via .ForEach({ $_.item })[2] - bypasses the problem, and accessing the .item property on each [XmlElement] then works as intended.

注意:XmlElements 也有一个原生类型 .Item 属性,但在 PowerShell 改编 XML DOM 的上下文中,逻辑是颠倒的:它是adapted 优先于类型原生属性的属性(后者可以作为带有 get_ 前缀的 methods 访问;例如,.get_Index()).

Note: XmlElements too have a type-native .Item property, but in the context of PowerShell's adaptation of the XML DOM the logic is reversed: it is the adapted properties that take precedence over the type-native ones (the latter can be accessed as methods with a get_ prefix; e.g., .get_Index()).

[1] 从技术上讲,参数化的 .Item 属性是通过 interface (IList) 公开的,但是 PowerShell 表面上是这样的显式接口实现属性就好像它们是类型的直接属性一样.

[1] Technically, the parameterized .Item property is exposed via an interface (IList), but PowerShell surfaces such explicit-interface-implementation properties as if they were direct properties of a type.

[2] 理想情况下,您可以使用 .ForEach('item') 作为更快的替代方案,但从 PowerShell (Core) 7.2 开始,这不起作用由于错误,在GitHub 问题 #15994 中有详细说明.

[2] Ideally, you'd be able to use .ForEach('item') as a faster alternative, but as of PowerShell (Core) 7.2 this doesn't work due to a bug, detailed in GitHub issue #15994.

这篇关于如何在powershell中获取深度深度xml值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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