0

行番号で 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 ファイルで検証するだけです。

4

1 に答える 1

1

PowerShell が独自の型でオブジェクトをラップする方法について、PowerShell のブラック マジックと戦っています:-(

キャッチした を見ると、実際にスローされたインスタンスを含むプロパティがあり、必要なプロパティとプロパティがあることSystem.Management.Automation.MethodInvocationExceptionがわかります。InnerExceptionSystem.Xml.Schema.XmlSchemaValidationExceptionXmlReaderLineNumberLinePosition

ただし、よりクリーンな方法は、最初に例外のみをキャッチ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)
于 2020-07-03T21:40:18.787 に答える