XML 隨處可見。儘管它使用了令人討厭的尖括號,但 XML 格式仍被廣泛使用。配置文件、RSS 訂閱、Office 文件(.docx 中的「x」)僅為部分列表。在 PowerShell 中使用 XML 文件進行解析是 PowerShell 旅程中的一個重要步驟。
本教程將向您展示如何使用 PowerShell 解析 XML 文件並對其進行驗證。這將使您在獲取和評估 XML 數據的所有方面上從零到英雄。您將獲得幫助您驗證 XML 數據完整性並在腳本執行之前停止錯誤數據的工具!
先決條件
為了跟隨所呈現的內容,您應該具備:
- PowerShell 版本3.0 及以上。這些示例是在 Windows PowerShell v5.1 上創建的
- Notepad++、Visual Studio Code 或其他理解 XML 的文本編輯器。
使用 Select-Xml
解析 PowerShell XML 元素
首先,讓我們先介紹使用 PowerShell 解析 XML 的最受歡迎和最簡單的方法之一,那就是使用 Select-Xml
。 Select-Xml
命令讓您可以提供一個 XML 文件或字符串,以及一個稱為 XPath 的「過濾器」,以提取特定信息。
XPath是一串元素名稱,它使用“路徑式”語法來識別和導航 XML 文件中的節點。
假設您有一個包含許多電腦的 XML 文件,並希望使用 PowerShell 解析此 XML 文件。每台電腦都有各種元素,如名稱、IP 地址和用於報告中的 Include
元素。
元素是一個具有開始標籤和結束標籤的 XML 片段,之間可能包含一些文本,例如
<Name>SRV-01</Name>
您想使用 PowerShell 解析此 XML 文件並獲取電腦名稱。為此,您可以使用 Select-Xml
命令。
在上面的文件中,電腦名稱出現在 Name 元素的內部文本(InnerXML)中。
InnerXML 是兩個元素標籤之間的文本。
為了找到電腦名稱,您首先需要提供適當的 XPath (/Computers/Computer/Name
)。此 XPath 語法將僅返回 Computer
元素下的 Name
節點。然後,使用 ForEach-Object
循環對每個元素的 Node.InnerXML
屬性進行操作,以獲取每個 Name
元素的 InnerXML。
使用 PowerShell 使用 Select-Xml
解析 XML 屬性
現在讓我們從不同角度來解決找到電腦名稱的問題。這一次,電腦描述符不再是用XML元素表示,而是用XML屬性表示。
屬性是一個鍵/值對,例如
name="SRV-01"
。屬性始終出現在開始標籤內,就在標籤名稱之後。
以下是使用屬性表示的電腦描述符的XML文件。現在您可以將每個描述符視為屬性而不是元素。
由於這一次每個描述符都是一個屬性,所以稍微修改XPath來僅查找電腦元素。然後,再次使用ForEach-Object
cmdlet,找到name屬性的值。
確實,這也帶來了相同的結果:SRV-01,SRV-02和SRV-03:

無論是讀取元素還是屬性,無論在哪種情況下,Select-Xml
的語法都很繁瑣:它強制您使用XPath
參數,然後將結果傳送到循環中,最後在Node屬性下查找數據。
幸運的是,PowerShell提供了一種更方便和直觀的讀取XML文件的方法。PowerShell可以讀取XML文件並將其轉換為XML對象。
相關資訊:使用PowerShell數據類型加速器加快編碼速度
將XML字符串轉換為對象
使用PowerShell解析XML的另一种方法是将XML转换为对象。最简单的方法是使用[xml]
类型加速器。
通过使用[xml]
前缀变量名,PowerShell将原始纯文本XML转换为可以使用的对象。
读取XML对象元素
现在$xmlElm
和$xmlAttr
变量都是XML对象,允许您通过点表示法引用属性。也许您需要找到每个计算机元素的IP地址。由于XML文件是一个对象,您可以通过简单地引用IP元素来实现。
从PowerShell 3.0版本开始,XML对象使用相同的语法读取属性值,就像读取元素的内部文本一样。因此,IP地址的值与元素文件完全相同的语法从属性文件中读取。
读取XML属性
使用完全相同的点表示法,您可以读取XML属性,尽管XML结构存在差异。
下面的结果显示两者获得了相同的数据,每个数据来自其相应的文件:

此外,使用对象,一旦它加载到内存中,即使您正在使用PowerShell ISE,您甚至可以获得智能感知进行选项卡自动完成。例如如下所示。

遍历XML数据
一旦您了解如何直接将XML文件读取为XML对象(利用[xml]
类型加速器),您就可以充分利用PowerShell对象的全部功能。
舉個例子,假設您需要遍歷 XML 檔案中所有具有 include=”true” 屬性的電腦,以檢查它們的連線狀態。以下程式碼展示了如何實現這一目標。
這段腳本的功能如下:
- 讀取檔案並轉換為 XML 物件。
- 遍歷相關電腦以獲取它們的連線狀態。
- 最後,將結果輸出物件發送到流程管道中。
上述腳本的結果如下:

XML 結構
在前一節中,您看到了兩種不同的 XML 檔案,它們以兩種不同的方式表示資料集。這些方式稱為 XML 結構。XML 結構定義了特定 XML 文件的合法構建塊:
- 該特定文件中可以出現的元素和屬性的名稱。
- 子元素的數量和順序。
- 元素和屬性的資料類型。
該結構基本上定義了 XML 的結構。
驗證 XML 資料
一個 XML 文件可能具有正確的語法(像 Notepad++ 這樣的編輯器會提醒),但其資料可能不符合項目要求。這就是模式起作用的地方。當您使用 XML 資料時,必須確保所有資料都根據定義的模式有效。
您最不希望的是在執行時發現資料錯誤,而此時程式碼可能已經在檔案系統和註冊表上執行了一些不可逆操作,且已經深入了 500 行。
那麼,如何事先檢查資料是否正確呢?讓我們先看看可能的錯誤類型。
XML 資料可能的錯誤
一般來說,XML 檔案中發現的錯誤屬於兩個類別:元資料錯誤和資料本身的錯誤。
XML 元資料錯誤
以下的文件 MorePeople.xml 在語法上是完全有效的。您可以看到該文件有一個名為 People 的元素(根元素),裡面包含三個 Person 元素。此結構是完全可以接受的。但它包含了一個例外,您能看到嗎?
如果您沒有看到,不用擔心,它只是被隱藏了起來。問題出現在第一個內部元素中:
原本應該是一個 Country,但被拼錯了,Canada 变成了 County。
XML 資料的錯誤
在修正了 Country 問題之後,MorePeople.xml 還出現了另一個問題:
元数据,即元素和属性,都没问题。那么问题出在哪里呢?这次问题还是出在第一个Person 行的一个值上。有人决定用yes来替代true,但是像下面的代码将无法获取第一个元素,因为它在寻找true,而不是yes:
创建一个XML模式
现在你已经知道可能出现的错误类型,是时候展示模式文件如何帮助了。第一步是创建一个示例数据文件。示例可以是最简单的例子,只包含一个内部元素。对于上面的示例,让我们创建一个像这样的示例文件People.xml:
现在在下面构建一个PowerShell函数并使用它与示例数据一起创建.xsd模式。
将该函数复制到您的ISE或您喜欢的Powershell编辑器中,加载到内存中并使用它来创建模式。有了加载函数后,创建模式的代码只有一行:
结果将显示新创建的模式的路径:

使用模式文件验证您的数据
請查看上面指定的位置。如果有 .xsd 文件,那麼您正在正確地看到驗證的過程。在確認步驟中,請使用以下函數:
將該函數加載到內存中,並使用它來驗證 MorePeople.xml 中的兩個錯誤示例。觸發驗證,請使用以下命令:
實際結果取決於 MorePeople.xml 的內容。
讓我們看兩個示例。請注意,當 MorePeople.xml 沒有錯誤時,上述函數將返回 True
。

當 MorePeople.xml 文件包含錯誤數據(將 Country 拼寫錯誤為 County)時,該函數將返回一些錯誤詳細信息並返回 False
。

正如您所見,冗長的輸出中指定的錯誤非常具有信息性:它指向了問題所在的文件,並指出了問題發生的確切組件。
微調驗證模式
讓我們看一下模式文件,然後看看如何使其更好。
由 New-XmlSchema
創建的默認模式如下:
上述默認模式是好的,但不完美。確實,它捕捉到了 Country 屬性的錯別字。但是,如果您保留模式不變,在其他預期未滿足的情況下,這些問題將不會被 Test-XmlBySchema
驗證報告為錯誤。讓我們解決這個問題。
下表列出了一些不被視為驗證錯誤且不會被Test-XmlBySchema
注意到的情況。在每一行中,右列顯示了如何手動更改模式以添加對所需保護的支援。
A modified version of the schema file, with all protections added, is shown right after the table.
添加到默認模式的設置-示例
Required Behavior | Relevant setting on the schema file |
At least one Person element | Set the minOccurs value of the Person element to 1 |
Make Name, Country and IsAdmin attributes mandatory | Add use=”required” to each of these attributes declaration |
Allow only true/false values for IsAdmin | Set type=”xs:boolean” for the IsAdmin declaration |
Allow only Country names between 3 and 40 characters | Use the xs:restriction (see detailed explanation after the schema text) |
在示例中,對於IsAdmin屬性,如果有布爾限制,其值必須是小寫true或false。
使用xs:restriction進行字符串長度驗證
字符串長度驗證有點複雜。因此,即使它在上面作為修改後的模式的一部分顯示出來,它仍然值得更多關注。
經手動添加use=”required”後,原始模式中Country屬性的項目如下所示:
要添加長度保護,您應該添加<xs:simpleType>
元素,並在其中添加<xs:restriction base="xs:string">
。此限制又包含在xs:minLength
和xs:minLength
上聲明的所需限制。
在所有這些更改之後,最終的xs:attribute
聲明從單行變成了一個巨大的8行節點:
如果在上面的解釋之後您的頭沒有暈眩,那麼您有權看到驗證的實際操作。為此,讓我們故意將值Canada縮短為兩個字符的音節:Ca
使用短國家名稱,並保存MorePeople.xml,然後您可以運行以下驗證命令:
而且結果確實顯示了複雜的架構已經發揮了作用:

XML架構驗證可以變得很複雜,可以驗證幾乎任何您能想到的模式,尤其是與正則表達式結合使用時。