powershell - 验证带有错误行号的 XML
问题描述
我正在尝试使用行号获取 XML 验证错误,并且存在 的LineNumberOffset
属性这一事实[xml.xmlReaderSettings]
表明这是可能的。但我似乎无法找到如何启用行号或在结果错误中访问行号。这谈到在 C# 中使用LoadOptions.SetLineInfo;
但当我尝试时这不是一个有效的属性$xmlReaderSettings.SetLineInfo = $true
。
function readXMLFile ([string]$path) {
$readXMLFile = [psCustomObject]@{
xml = [xml.xmlDocument]::New()
error = $null
}
$fileStream = $null
$xmlreader = $null
$importFile = [xml.xmlDocument]::New()
$xmlReaderSettings = [xml.xmlReaderSettings]::New()
#$xmlReaderSettings.ignoreComments = $true
$xmlReaderSettings.closeInput = $true
$xmlReaderSettings.prohibitDtd = $false
$xmlReaderSettings.ValidationType = [System.Xml.ValidationType]::Schema
$xmlReaderSettings.ValidationFlags = [System.Xml.Schema.XmlSchemaValidationFlags]::ProcessInlineSchema -bor
[System.Xml.Schema.XmlSchemaValidationFlags]::ProcessSchemaLocation -bor
[System.Xml.Schema.XmlSchemaValidationFlags]::ReportValidationWarnings
$xmlReaderSettings.Schemas.Add($Null, $SchemaFile)
try {
$fileStream = [io.fileStream]::New($path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite)
$xmlreader = [xml.xmlreader]::Create($fileStream, $xmlReaderSettings)
$importFile.Load($xmlreader)
} catch {
$exceptionName = $_.exception.GetType().name
$exceptionMessage = $_.exception.message
switch ($exceptionName) {
MethodInvocationException {
if ($exceptionMessage -match ': "(?<string>.*)"$') {
$readXMLFile.error = "Error loading XML; $($matches['string'])"
} else {
$readXMLFile.error = "Error loading XML; $exceptionMessage"
}
}
Default {
$readXMLFile.error = "Error loading XML; $($exceptionName) - $exceptionMessage" # Or just the message?
}
}
} finally {
if ($xmlreader) {
$xmlreader.Dispose()
}
if ($readXMLFile.error) {
$readXMLFile.xml = $null
} else {
$readXMLFile.xml = $importFile
}
}
return $readXMLFile
}
编辑:我一直在研究的架构是
<?xml version = "1.0"?>
<xs:schema xmlns:xs = "http://www.w3.org/2001/XMLSchema">
<xs:element name = 'Definitions'>
<xs:complexType>
<xs:sequence>
<xs:element name = 'Sets' type = 'Sets' minOccurs = '0' maxOccurs = '1' />
<xs:element name = 'Packages' type = 'Packages' minOccurs = '0' maxOccurs = '1' />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name = 'Sets'>
<xs:sequence>
<xs:element name = "Set" type = 'Set' minOccurs = '0' maxOccurs='unbounded' />
</xs:sequence>
</xs:complexType>
<xs:complexType name = 'Set'>
<xs:sequence>
<xs:element name = 'Set' type='xs:string' minOccurs = '0' maxOccurs='unbounded' />
<xs:element name = 'Package' type='xs:string' minOccurs = '0' maxOccurs='unbounded' />
<xs:element name = 'Rollout' type='xs:string' minOccurs = '0' maxOccurs='unbounded' />
<xs:element name = 'Remove' type='xs:string' minOccurs = '0' maxOccurs='unbounded' />
</xs:sequence>
<!--<xs:attribute name = 'id' type = 'xs:string'/>-->
</xs:complexType>
<xs:complexType name = 'Packages'>
<xs:sequence>
<xs:element name = 'Package' type = 'Package' minOccurs = '0' maxOccurs='unbounded' />
</xs:sequence>
<xs:attribute name = 'id' type = 'xs:string'/>
</xs:complexType>
<xs:complexType name = 'Package'>
<xs:sequence>
<xs:element name = 'Package' type='xs:string' minOccurs = '0' maxOccurs='unbounded' />
<xs:element name = 'Task' type='Task' minOccurs = '0' maxOccurs='unbounded' />
</xs:sequence>
</xs:complexType>
<xs:complexType name = 'Task'>
<xs:sequence>
<xs:element name = 'PreProcess' type='TaskPrePostProcess' minOccurs = '0' maxOccurs='1' />
<xs:element name = 'Process' type='TaskProcess' minOccurs = '1' maxOccurs='1' />
<xs:element name = 'PostProcess' type='TaskPrePostProcess' minOccurs = '0' maxOccurs='1' />
</xs:sequence>
</xs:complexType>
<xs:complexType name = 'TaskPrePostProcess'>
<xs:sequence>
<xs:element name = 'Task' type='Task' minOccurs = '0' maxOccurs='unbounded' />
</xs:sequence>
</xs:complexType>
<xs:complexType name = 'TaskProcess'>
</xs:complexType>
</xs:schema>
一些简单的样本数据将是
<?xml version="1.0" encoding="utf-8" ?>
<Definitions>
<Sets>
<Set id="Arch">
<Package>DTV_2017</Package>
</Set>
<Set id="Px_Arch">
<Package>RVT_2017</Package>
<Package>RVT_2018</Package>
</Set>
</Sets>
<Packages>
</Packages>
</Definitions>
编辑:有趣的是,当我删除验证并捕获格式错误的 XML 错误时,我确实得到了行号。它仅使用 XSD 文件进行验证,该文件会产生不是特别有用的错误。
解决方案
您正在与 PowerShell 的一些黑魔法作斗争,它有时会使用自己的类型包装对象:-(
。
如果你看一下System.Management.Automation.MethodInvocationException
你捕获的,你会看到它有一个InnerException
属性,其中包含实际抛出的System.Xml.Schema.XmlSchemaValidationException
实例,并且有你想要的and属性。XmlReader
LineNumber
LinePosition
但是,一种更简洁的方法是首先只捕获XmlSchemaValidationException
异常,然后让其他一切都抛出。这样,PowerShell 会为您提供原始异常而不是其包装器:
catch [System.Xml.Schema.XmlSchemaValidationException]
{
$ex = $_.Exception;
$type = $ex.GetType().FullName;
$lineNumber = $ex.LineNumber;
$linePosition = $ex.LinePosition;
$message = $ex.Message;
write-host "type = $type";
write-host "line = $lineNumber";
write-host "position = $linePosition";
write-host "message = $message";
...
}
输出:
type = System.Xml.Schema.XmlSchemaValidationException
line = 4
position = 14
message = The 'id' attribute is not declared.
顺便说一句,您可能还想从中捕获返回值,$xmlReaderSettings.Schemas.Add($Null, $SchemaFile)
否则它将被写入函数的输出流,并会给出一些奇怪的结果......
$null = $xmlReaderSettings.Schemas.Add($Null, $SchemaFile)
推荐阅读
- powerbi - 在 Power Query 中创建 DATEID 列会导致堆栈溢出
- java - 在 Android RecycleView 中隐藏一行
- python - np.savetxt 没有写入整个数组
- python - 将外部客户端连接到 Docker websocket
- python - 联合训练模型:您传递给模型的 Numpy 数组列表不是模型预期的大小
- java - 使用 Spring JPA/Hibernate Entity 将列表中的值与输入字符串值进行比较
- python - 如何返回值最接近输入值的列
- c++ - testthat (& Catch) 抱怨 R CMD 检查缺少 xml2 库
- group-by - Dask Groupby 多指标级别
- linux - 通过 ssh 建立 socat 连接以连接到远程虚拟 COM 端口上的设备