如何用PowerShell 5.1验证包含内联Schema的XML?
我创建了包含内联Schema的XML文件,并编写PowerShell脚本验证它,但每次都失败。不确定问题出在XML还是验证脚本——我复制了微软的inline-namespaced.xml示例,用LINQ to XML脚本验证显示有效,但把book元素重命名为Schema未定义的books后,脚本仍显示有效!查相关问题得知,当Schema的targetNamespace和文档不匹配时,LINQ to XML会默认通过验证。于是我改用XmlReader写脚本,但还是无法验证微软的基础示例,提示:Line 2, Pos 2, Could not find schema information for the element 'catalog',连根元素都报错。显然操作有误,但问题到底出在哪?
inline-namespaced.xml
<?xml version="1.0"?> <catalog xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:x="urn:book"> <!-- START OF SCHEMA --> <xsd:schema targetNamespace="urn:book"> <xsd:element name="book"> <xsd:complexType> <xsd:sequence> <xsd:element name="author" type="xsd:string"/> <xsd:element name="title" type="xsd:string"/> <xsd:element name="genre" type="xsd:string"/> <xsd:element name="price" type="xsd:float"/> <xsd:element name="publish_date" type="xsd:date"/> <xsd:element name="description" type="xsd:string"/> </xsd:sequence> <xsd:attribute name="id" type="xsd:string"/> </xsd:complexType> </xsd:element> </xsd:schema> <!-- END OF SCHEMA --> <x:book id="bk101"> <author>Gambardella, Matthew</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> </x:book> </catalog>
使用XmlReader的PowerShell 5.1脚本
# Load the XML content $xmlFile = "C:\Temp\inline-namespaced.xml" # Prepare the event handler for validation errors $eventHandler = { param ($sender, $eventArgs) Write-Host $("Line {0}, Pos {1}, {2}" -f $eventArgs.Exception.LineNumber, $eventArgs.Exception.LinePosition, $eventArgs.Exception.Message) } # Create XmlReaderSettings and enable schema validation $settings = New-Object System.Xml.XmlReaderSettings $settings.ValidationType = [System.Xml.ValidationType]::Schema $settings.ValidationFlags = [System.Xml.Schema.XmlSchemaValidationFlags]::ProcessInlineSchema -bor [System.Xml.Schema.XmlSchemaValidationFlags]::ReportValidationWarnings # Attach the event handler $settings.add_ValidationEventHandler($eventHandler) # Create the XmlReader with the settings $reader = [System.Xml.XmlReader]::Create($xmlFile, $settings) # Read through the XML content to trigger validation while ($reader.Read()) { } $reader.Close()
核心问题1:根元素catalog无Schema约束
你的内联Schema只定义了urn:book命名空间下的book元素,根元素catalog属于无命名空间,没有任何Schema对它进行约束,所以XmlReader会提示找不到该元素的Schema信息。这是正常警告,若目标仅验证x:book元素,可忽略该警告;若要验证整个文档,需给根元素添加Schema定义。
核心问题2:LINQ to XML验证失效的原因
LINQ to XML默认不强制要求元素必须匹配Schema,仅当明确指定验证规则时才会严格检查。当你把x:book改成x:books时,由于没有Schema定义该元素,本该报错,但LINQ to XML默认不校验无匹配Schema的元素,因此误判为有效。
修正后的验证方案
方案1:忽略根元素警告,专注验证x:book
修改脚本的事件处理器,过滤掉根元素catalog的警告,只处理错误和book相关的警告:
$xmlFile = "C:\Temp\inline-namespaced.xml" $eventHandler = { param ($sender, $eventArgs) # 过滤catalog元素的无Schema警告 if ($eventArgs.Severity -eq [System.Xml.Schema.ValidationSeverity]::Error -or ($eventArgs.Severity -eq [System.Xml.Schema.ValidationSeverity]::Warning -and $eventArgs.Exception.Message -notlike "*catalog*")) { Write-Host $("Line {0}, Pos {1}, {2}" -f $eventArgs.Exception.LineNumber, $eventArgs.Exception.LinePosition, $eventArgs.Exception.Message) } } $settings = New-Object System.Xml.XmlReaderSettings $settings.ValidationType = [System.Xml.ValidationType]::Schema $settings.ValidationFlags = [System.Xml.Schema.XmlSchemaValidationFlags]::ProcessInlineSchema -bor [System.Xml.Schema.XmlSchemaValidationFlags]::ReportValidationWarnings $settings.add_ValidationEventHandler($eventHandler) $reader = [System.Xml.XmlReader]::Create($xmlFile, $settings) while ($reader.Read()) { } $reader.Close()
此时将x:book改为x:books,脚本会触发明确的错误提示,指出books元素未被Schema定义。
方案2:给根元素添加Schema约束
若要验证整个XML文档,修改内联Schema,添加对无命名空间catalog元素的定义:
<?xml version="1.0"?> <catalog xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:x="urn:book"> <!-- START OF SCHEMA --> <xsd:schema targetNamespace="urn:book" xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <!-- 定义无命名空间的catalog元素 --> <xsd:element name="catalog" xmlns=""> <xsd:complexType> <xsd:sequence> <!-- 允许内联Schema元素 --> <xsd:element ref="xsd:schema" minOccurs="0"/> <!-- 引用urn:book命名空间的book元素 --> <xsd:element ref="x:book"/> </xsd:sequence> </xsd:complexType> </xsd:element> <!-- 原有的book元素定义 --> <xsd:element name="book"> <xsd:complexType> <xsd:sequence> <xsd:element name="author" type="xsd:string"/> <xsd:element name="title" type="xsd:string"/> <xsd:element name="genre" type="xsd:string"/> <xsd:element name="price" type="xsd:float"/> <xsd:element name="publish_date" type="xsd:date"/> <xsd:element name="description" type="xsd:string"/> </xsd:sequence> <xsd:attribute name="id" type="xsd:string"/> </xsd:complexType> </xsd:element> </xsd:schema> <!-- END OF SCHEMA --> <x:book id="bk101"> <author>Gambardella, Matthew</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> </x:book> </catalog>
修改后,XmlReader会验证整个文档,包括根元素和x:book,修改book为books时会直接报错。
内容的提问来源于stack exchange,提问作者Wim

