I am trying to get XML validation errors with line numbers, and the fact that there is a LineNumberOffset
property of [xml.xmlReaderSettings]
suggests this is possible. But I can't seem to find how to either enable line numbers, or access line numbers in the resultant error. This talks about doing it in C# with LoadOptions.SetLineInfo;
but that's not a valid property when I try $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
}
EDIT: The schema I have been working on is
<?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>
And some simple sample data would be
<?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>
EDIT: Interestingly, when I remove the validation and just catch malformed XML errors, I DO get line numbers. It's only validating with the XSD file that produces errors that aren't particularly helpful.