如何在 Powershell REPL 控制台中打印 xml 元素及其属性的列表?

How to print a list of xml elements and their properties in the Powershell REPL console?

引用:

https://www.red-gate.com/simple-talk/sysadmin/powershell/powershell-data-basics-xml/

和:

如何打印元素列表及其属性?

PS /home/nicholas/powershell> 
PS /home/nicholas/powershell> $doc = new-object System.Xml.XmlDocument
PS /home/nicholas/powershell> $file = resolve-path('./bookstore.xml') 
PS /home/nicholas/powershell> $doc.load($file)                                           
PS /home/nicholas/powershell> 
PS /home/nicholas/powershell> $doc.bookstore.book[1].author.first-name
ParserError: 
Line |
   1 |  $doc.bookstore.book[1].author.first-name
     |                                     ~~~~~
     | Unexpected token '-name' in expression or statement.

PS /home/nicholas/powershell> 
PS /home/nicholas/powershell> $doc.bookstore.book[1].author           

first-name last-name
---------- ---------
Margaret   Atwood

PS /home/nicholas/powershell> 
PS /home/nicholas/powershell> $doc.bookstore

bk          book
--          ----
urn:samples {book, book, book, book}

PS /home/nicholas/powershell> 

只是没有使用 books:

PS /home/nicholas/powershell> 
PS /home/nicholas/powershell> $doc.bookstore.book

genre           : novel
publicationdate : 1997
ISBN            : 1-861001-57-8
title           : Pride And Prejudice
author          : author
price           : 24.95

genre           : novel
publicationdate : 1992
ISBN            : 1-861002-30-1
title           : The Handmaid's Tale
author          : author
price           : 29.95

genre           : novel
publicationdate : 1991
ISBN            : 1-861001-57-6
title           : Emma
author          : author
price           : 19.95

genre           : novel
publicationdate : 1982
ISBN            : 1-861001-45-3
title           : Sense and Sensibility
author          : author
price           : 19.95


PS /home/nicholas/powershell> 

哎呀。

解决问题中显示的语法错误:

# BROKEN: `first-name` cannot be used without quoting
$doc.bookstore.book[1].author.first-name

# OK:
$doc.bookstore.book[1].author.'first-name'

元素名称 first-name,在 PowerShell 中显示为 属性 名称,不能在没有引号的情况下使用 ,因为 - 然后被解释为 减法运算符 ,导致您看到的错误。

简而言之:

  • 在不带引号的 属性 名称中只能使用字母、数字和 _(下划线);不加引号的 变量名 .[1]

    同上
  • 如有疑问,引用


[1] PowerShell 中标识符名称的确切规则:

更准确地说,如果标识符 由以下 Unicode 类别 之一的字符组成,PowerShell 允许不加引号(在 .NET 中定义为括号中列出的枚举 System.Globalization.UnicodeCategory; the two-letter shorthands 可以与正则表达式中的 \p{<shortCategoryName>} 一起使用:

标识符的类型

  • 属性 姓名 (.foo)
  • 哈希表文字中的键 (@{ foo = ... })
  • 变量名 ($foo)

标识符支持额外的字符,但需要额外的语法:

不符合上述规则的标识符必须是:

  • 属性 names and hashtable keys: quoted ('last-name' or "last-name")
  • 变量名:包含在{...}中(${last-name}

请注意,扩展规则适用于命令名称(函数名称、cmdlet、脚本或可执行文件及其别名) 模块名称:

  • 除上述之外,以下允许不加引号
    • -(“连字符”、“减号”、松散的:“破折号”)
    • .(“句号”,“句号”)
    • 在文件 paths 中还有:\) and /)

在命令名称中,除了函数和 cmdlet 名称(您甚至不能 define 使用其他字符),您可以在名称中使用其他字符,如只要您在调用时引用命令名称。

但是,这样做是不明智的,因为用户通常希望命令不需要这样的引用;使用人为的示例:Set-Alias 'a&b' Get-Date; & 'a&b' 在技术上可行,但调用的笨拙(引用,然后需要 &)使它成为一个糟糕的选择。

解决显示格式问题:

如果您仔细查看示例输出 ,您会发现即使显示 大部分 有用,author 属性 是 author 而不是显示(假定的)first-namelast-name 子元素值。

问题是 PowerShell 的默认输出格式表示具有 :

的子元素
  • 至少一个属性
  • and/or至少一个子元素本身

仅由元素的名称

尤其是 具有深层嵌套的元素,这会导致 无用的输出

解决方法,可能组合使用:

  • 访问.OuterXml.InnerXml属性等元素,其中包含完整的XML 元素的文本 带有/不带有元素标签本身。

    • 鉴于 XML 文本是 单行 表示 不是 印刷精美。

    • 您可以.OuterXml / InnerXml 值传递给 漂亮打印 函数需要一些额外的工作,但是,因为 PowerShell 没有直接公开此类功能。

  • 使用Select-Object (or, for display purposes only, a Format-* cmdlet such as Format-Table) with .

    • 虽然这允许您完全控制显示的内容,但工作量更大。

参见下面的示例。


# Sample XML document
$xmlDoc = [xml] @"
<?xml version="1.0"?>
<bookstore>
   <book id="bk101">
      <author>
        <first-name>Matthew</first-name>
        <last-name>Gambardella</last-name>
      </author>
      <title>XML Developer's Guide</title>
      <genre>Computer</genre>
      <price>44.95</price>
      <publish_date>2000-10-01</publish_date>
      <description>An in-depth look at creating applications with XML.</description>
   </book>
   <book id="bk102">
      <author>
        <first-name>Kim</first-name>
        <last-name>Rall</last-name>
      </author>
      <title>Midnight Rain</title>
      <genre>Fantasy</genre>
      <price>5.95</price>
      <publish_date>2000-12-16</publish_date>
      <description>A former architect battles corporate zombies, an evil sorceress, and her own childhood to become queen of the world.</description>
   </book>
</bookstore>
"@

获得所有 <book> 元素的有用表示 ,包括 <author> 子元素的 <first-name><last-name> 子元素 通过 Select-Object 和计算的 属性:

$xmldoc.bookstore.book | Select-Object id, 
   @{ n='author'; e={ $_.author.'first-name' + ' ' + $_.author.'last-name'} }, 
   title, genre, price, publish_date, description

这会产生(注意 author 属性 现在如何列出名字和姓氏):

id           : bk101
author       : Matthew Gambardella
title        : XML Developer's Guide
genre        : Computer
price        : 44.95
publish_date : 2000-10-01
description  : An in-depth look at creating applications with XML.

id           : bk102
author       : Kim Rall
title        : Midnight Rain
genre        : Fantasy
price        : 5.95
publish_date : 2000-12-16
description  : A former architect battles corporate zombies, an evil sorceress, and her own childhood to become queen of the world.

通过辅助 System.Xml.Linq.XDocument 实例通过 漂亮打印 XML 获得所有 <book> 元素的有用表示:

# Load the assembly that contains XDocument.
# Note: Required in Windows PowerShell only, and only once per session.
Add-Type -AssemblyName System.Xml.Linq

$xmldoc.bookstore.book | ForEach-Object {
  ([System.Xml.Linq.XDocument] $_.OuterXml).ToString()
}

这会产生(印刷精美的 XML 表示):

<book id="bk101">
  <author>
    <first-name>Matthew</first-name>
    <last-name>Gambardella</last-name>
  </author>
  <title>XML Developer's Guide</title>
  <genre>Computer</genre>
  <price>44.95</price>
  <publish_date>2000-10-01</publish_date>
  <description>An in-depth look at creating applications with XML.</description>
</book>
<book id="bk102">
  <author>
    <first-name>Kim</first-name>
    <last-name>Rall</last-name>
  </author>
  <title>Midnight Rain</title>
  <genre>Fantasy</genre>
  <price>5.95</price>
  <publish_date>2000-12-16</publish_date>
  <description>A former architect battles corporate zombies, an evil sorceress, and her own childhood to become queen of the world.</description>
</book>

请注意,您可以将格式化代码包装在一个名为 Format-Xml 的简单(过滤器)函数中,您可以将其放入 $PROFILE 文件(在 Windows PowerShell,也把 Add-Type -AssemblyName System.Xml.Linq 放在那里,在它上面):

filter Format-Xml { ([System.Xml.Linq.XDocument] $_.OuterXml).ToString() }

现在格式很简单:

$xmldoc.bookstore.book | Format-Xml