2017-06-02 3 views
3

C#XDocument.ValidateまたはXMLReaderSettingsを使用して、有効なXSDに対してXML文書を検証するという、本当に奇妙な問題があります。問題は次のとおりです。XML文書にエラーがある場合、検証プロセスは特定の条件下ですべてのエラーを捕らえることができず、このアノーマリーのパターンを見つけることができません。ここでXDocument.ValidateがXSDに対してすべてのエラーをキャッチしていない

は私のXSDです:

<?xml version="1.0" encoding="utf-8"?> 
 
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" 
 
\t \t \t targetNamespace="http://www.somesite.com/somefolder/messages" 
 
\t \t \t xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
 
    <xs:element name="Message"> 
 
    <xs:complexType> 
 
    <xs:sequence> 
 
     <xs:element name="Header"> 
 
     <xs:complexType> 
 
      <xs:sequence> 
 
      <xs:element name="MessageId" type="xs:string" /> 
 
      <xs:element name="MessageSource" type="xs:string" /> 
 
      </xs:sequence> 
 
     </xs:complexType> 
 
    </xs:element> 
 
    <xs:element name="Body"> 
 
     <xs:complexType> 
 
      <xs:sequence> 
 
      <xs:element name="Abc001"> 
 
       <xs:complexType> 
 
        <xs:sequence> 
 
        <xs:element name="Abc002" type="xs:string" /> 
 
        <xs:element name="Abc003" type="xs:string" minOccurs="0" /> 
 
        <!--<xs:element name="Abc004" type="xs:string" />--> 
 
        <xs:element name="Abc004"> 
 
         <xs:simpleType> 
 
         <xs:restriction base="xs:string"> 
 
          <xs:maxLength value="200"/> 
 
         </xs:restriction> 
 
         </xs:simpleType> 
 
        </xs:element> 
 
         <xs:element name="Abc005"> 
 
         <xs:complexType> 
 
          <xs:sequence> 
 
           <xs:element name="Abc006" type="xs:unsignedShort" /> 
 
           <xs:element name="Abc007"> 
 
           <xs:complexType> 
 
            <xs:sequence> 
 
            <xs:element name="Abc008" type="xs:string"/> 
 
            <xs:element name="Abc009" type="xs:string" minOccurs="0"/> 
 
            <xs:element name="Abc010" type="xs:string"/> 
 
            </xs:sequence> 
 
           </xs:complexType> 
 
           </xs:element> 
 
           <xs:element name="Abc011" type="xs:date" /> 
 
           <xs:element name="Abc012"> 
 
           <xs:complexType> 
 
            <xs:sequence> 
 
            <xs:element name="Abc013" type="xs:string" /> 
 
            <xs:element name="Abc014" type="xs:string" /> 
 
            </xs:sequence> 
 
           </xs:complexType> 
 
           </xs:element> 
 
          </xs:sequence> 
 
         </xs:complexType> 
 
         </xs:element> 
 
        </xs:sequence> 
 
       </xs:complexType> 
 
      </xs:element> 
 
      </xs:sequence> 
 
     </xs:complexType> 
 
    </xs:element> 
 
    </xs:sequence> 
 
    </xs:complexType> 
 
</xs:element> 
 
</xs:schema>

そして、ここでは、このXSDに対して検証されたXMLドキュメントです:

<?xml version="1.0" encoding="utf-8"?> 
 
<Message xmlns="http://www.somesite.com/somefolder/messages"> 
 
\t <Header> 
 
\t \t <MessageId>Lorem</MessageId> 
 
\t \t <MessageSource>Ipsum</MessageSource> 
 
\t </Header> 
 
\t <Body> 
 
\t \t <Abc001> 
 
\t \t \t <Abc002>dolor</Abc002> 
 
\t \t \t <Abc003>sit amet</Abc003> 
 
\t \t \t <Abc004>consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</Abc004> 
 
\t \t \t <Abc005> 
 
\t \t \t \t <Abc006>1234</Abc006> 
 
\t \t \t \t <Abc007> 
 
\t \t \t \t \t <Abc008>Ut enim</Abc008> 
 
\t \t \t \t \t <Abc009>ad</Abc009> 
 
\t \t \t \t \t <Abc010>minim</Abc010> 
 
\t \t \t \t </Abc007> 
 
\t \t \t \t <Abc011>1982-10-17</Abc011> 
 
\t \t \t \t <Abc012> 
 
\t \t \t \t \t <Abc013>veniam</Abc013> 
 
\t \t \t \t \t <Abc014>nostrud</Abc014> 
 
\t \t \t \t </Abc012> 
 
\t \t \t </Abc005> 
 
\t \t </Abc001> 
 
\t </Body> 
 
</Message>

今、XMLにいくつかの検証エラーを導入し、それをXSDに対して検証すると、すべてのエラーが予想通りに見つかる。ここでエラーが発生しやすいXMLが(エラーが導入されている場合、私はマークされている)である:

<?xml version="1.0" encoding="utf-8"?> 
 
<Message xmlns="http://www.somesite.com/somefolder/messages"> 
 
\t <Header> 
 
\t \t <MessageId>Lorem</MessageId> 
 
\t \t <MessageSource>Ipsum</MessageSource> 
 
\t </Header> 
 
\t <Body> 
 
\t \t <Abc001> 
 
\t \t \t <Abc002>dolor</Abc002> 
 
\t \t \t <Abc003>sit amet</Abc003> 
 
\t \t \t 
 
\t \t \t <!--The value for Abc004 is increased beyond the allowed 200 characters--> 
 
\t \t \t 
 
\t \t \t <Abc004>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</Abc004> 
 
\t \t \t <Abc005> 
 
\t \t \t \t <Abc006>1234</Abc006> 
 
\t \t \t \t <Abc007> 
 
\t \t \t \t \t <Abc008>Ut enim</Abc008> 
 
\t \t \t \t \t <ABC009>AD</ABC009> 
 
\t \t \t \t \t 
 
\t \t \t \t \t <!--<Abc010>minim</Abc010> Required element removed--> 
 
\t \t \t \t </Abc007> 
 
\t \t \t \t 
 
\t \t \t \t <!--Date formate below is wrong--> 
 
\t \t \t \t <Abc011>1982-10-37</Abc011> 
 
\t \t \t \t 
 
\t \t \t \t <Abc012> 
 
\t \t \t \t \t <Abc013>veniam</Abc013> 
 
\t \t \t \t \t <Abc014>nostrud</Abc014> 
 
\t \t \t \t </Abc012> 
 
\t \t \t </Abc005> 
 

 
\t \t \t <!--the element below is not allowed--> 
 
\t \t \t <Abc15>Not allowed</Abc15> 
 
\t \t </Abc001> 
 
\t </Body> 
 
</Message>

、ここではすべてのエラーを示して、私の結果のXMLです:

<MessageResponse xmlns="http://www.somesite.com/somefolder/messages"> 
 
    <Result>false</Result> 
 
    <Status>Failed</Status> 
 
    <FaultCount>4</FaultCount> 
 
    <Faults> 
 
     <Fault> 
 
      <FaultCode>ERR01</FaultCode> 
 
      <FaultMessage>The 'http://www.somesite.com/somefolder/messages:Abc004' element is invalid - The value 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.' is invalid according to its datatype 'String' - The actual length is greater than the MaxLength value.</FaultMessage> 
 
     </Fault> 
 
     <Fault> 
 
      <FaultCode>ERR02</FaultCode> 
 
      <FaultMessage>The element 'Abc007' in namespace 'http://www.somesite.com/somefolder/messages' has invalid child element 'ABC009' in namespace 'http://www.somesite.com/somefolder/messages'. List of possible elements expected: 'Abc009, Abc010' in namespace 'http://www.somesite.com/somefolder/messages'.</FaultMessage> 
 
     </Fault> 
 
     <Fault> 
 
      <FaultCode>ERR03</FaultCode> 
 
      <FaultMessage>The 'http://www.somesite.com/somefolder/messages:Abc011' element is invalid - The value '1982-10-37' is invalid according to its datatype 'http://www.w3.org/2001/XMLSchema:date' - The string '1982-10-37' is not a valid Date value.</FaultMessage> 
 
     </Fault> 
 
     <Fault> 
 
      <FaultCode>ERR04</FaultCode> 
 
      <FaultMessage>The element 'Abc001' in namespace 'http://www.somesite.com/somefolder/messages' has invalid child element 'Abc15' in namespace 'http://www.somesite.com/somefolder/messages'.</FaultMessage> 
 
     </Fault> 
 
    </Faults> 
 
</MessageResponse>

ここは奇妙な部分です。 "Abc001"要素の先頭にもう一度エラーを導入し、既存のエラーをすべて残してしまうと、結果が完全に乱れてしまいます。ここで新たに導入されたエラーとXMLです:

<?xml version="1.0" encoding="utf-8"?> 
 
<Message xmlns="http://www.somesite.com/somefolder/messages"> 
 
\t <Header> 
 
\t \t <MessageId>Lorem</MessageId> 
 
\t \t <MessageSource>Ipsum</MessageSource> 
 
\t </Header> 
 
\t <Body> 
 
\t \t <Abc001> 
 
\t \t \t <!--newly introduced error - removed the following element--> 
 
\t \t \t <!--<Abc002>dolor</Abc002>--> 
 
\t \t \t <Abc003>sit amet</Abc003> 
 
\t \t \t <!--The value for Abc004 is increased beyond the allowed 200 characters--> 
 
\t \t \t <Abc004>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</Abc004> 
 
\t \t \t <Abc005> 
 
\t \t \t \t <Abc006>1234</Abc006> 
 
\t \t \t \t <Abc007> 
 
\t \t \t \t \t <Abc008>Ut enim</Abc008> 
 
\t \t \t \t \t <ABC009>AD</ABC009> 
 
\t \t \t \t \t <!--<Abc010>minim</Abc010>--> 
 
\t \t \t \t </Abc007> 
 
\t \t \t \t <Abc011>1982-10-37</Abc011> 
 
\t \t \t \t <Abc012> 
 
\t \t \t \t \t <Abc013>veniam</Abc013> 
 
\t \t \t \t \t <Abc014>nostrud</Abc014> 
 
\t \t \t \t </Abc012> 
 
\t \t \t </Abc005> 
 
\t \t \t <!--the element below is not allowed--> 
 
\t \t \t <Abc15>Not allowed</Abc15> 
 
\t \t </Abc001> 
 
\t </Body> 
 
</Message>

は、最終的には、ここでの検証結果は次のとおりです。

<MessageResponse xmlns="http://www.somesite.com/somefolder/messages"> 
 
    <Result>false</Result> 
 
    <Status>Failed</Status> 
 
    <FaultCount>1</FaultCount> 
 
    <Faults> 
 
     <Fault> 
 
      <FaultCode>ERR01</FaultCode> 
 
      <FaultMessage>The element 'Abc001' in namespace 'http://www.somesite.com/somefolder/messages' has invalid child element 'Abc003' in namespace 'http://www.somesite.com/somefolder/messages'. List of possible elements expected: 'Abc002' in namespace 'http://www.somesite.com/somefolder/messages'.</FaultMessage> 
 
     </Fault> 
 
    </Faults> 
 
</MessageResponse>

ここに私のC#のコードです検証に使用しています:

public async Task<IMIDPreValidationAckMessage> ValidateXmlMessage(XDocument doc) 
    { 
     var result = new PreValidationAckMessage(); 
     result.Result = true; 
     result.Status = "Succeeded"; 

     var xsd = HttpContext.Current.Server.MapPath("~/message01.xsd"); 

     try 
     { 
      var uri = new System.Uri(xsd); 

      var localPath = uri.LocalPath; 

      var docNameSpace = doc.Root.Name.Namespace.NamespaceName; 

      XmlSchemaSet schemas = new XmlSchemaSet(); 
      schemas.Add(docNameSpace, localPath); 

      XmlReaderSettings xrs = new XmlReaderSettings(); 
      xrs.ValidationType = ValidationType.Schema; 
      xrs.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings; 
      xrs.Schemas = schemas; 

      result.XSDNamespace = doc.Root.GetDefaultNamespace().NamespaceName; 
      var errCode = 1; 

      xrs.ValidationEventHandler += (s, e) => 
      { 
       var msg = e.Message; 
       result.Result = false; 
       result.Status = "Failed"; 
       result.FaultCount++; 
       result.Faults.Add(new Fault 
       { 
        FaultCode = "ERR" + errCode++.ToString().PadLeft(2, '0'), 
        FaultMessage = e.Message 
       }); 
      }; 

      using (XmlReader xr = XmlReader.Create(doc.CreateReader(), xrs)) 
      { 
       while (xr.Read()) { } 
      } 
     } 
     catch (System.Exception ex) 
     { 
      result.Result = false; 
      result.Status = "Unknown Error"; 
     } 
     return result; 
    } 

ここで間違っていることを教えてもらえますか?

+0

最後のスニペットにすべてのクラスを含めて、コピーペーストして実行できるようにするとよいでしょう。 – Evk

+0

@Evk:迅速な返信をありがとう。私が投稿しなかったコードはネストされたクラスであり、ここでは本当に無関係です。 validationeventhandler内の文字列のリストにエラーメッセージを追加するだけであれば、テストで十分です。私のコードでは、エラーメッセージを収集し、別のXMLドキュメントを作成しています。それで全部です。 –

答えて

1

XmlReaderは、最初に遭遇したエラーで要素の検証を停止するようです。ここでは、古い(陳腐化)XmlValidatingReaderValidationEventHandlerの説明へのリンクです:

If an element reports a validation error, the rest of the content model for that element is not validated, however, its children are validated. The reader only reports the first error for a given element.

は、そして、それは(そのドキュメントが明示的に言及していないが)通常のXmlReaderと同じであるようです。

最初の例では、エラーは最も内側の要素(要素の無効なテキスト値など)または最後の子要素にあるため、すべて報告され、何もスキップされません。しかし、最後の例では、ルートAbc001要素の先頭にエラーが導入されるため、Abc001の残りの部分はすべてのエラーと共にスキップされます。

+0

もう一度お返事ありがとうございます。 Validationが要素ツリー全体に行き渡り、すべてのエラーを報告しているという印象を受けていましたが、なんと言っても意味があります。他のフィードバックがあれば私はもう少しお待ちしています。他に説明がない場合、私はあなたの回答を受け入れられた回答としてマークします。ありがとう。 –

+0

これを確認するには、ツリーのさまざまな部分にエラーを導入します。検証は、一般的に最初のエラーで停止するのではなく、指定されたサブツリー(要素)の最初のエラーでのみ終了します。あなたの最後の例では、複数の 'Abc001'要素を持っていれば、最初の要素だけをスキップします(最初はエラーがあるので)。 ''要素の直後にエラーを導入すると、この時点まで 'Abc005'の内容を解析します。 – Evk

+0

この質問に戻って答えをマークするのを忘れました。ごめんなさい!他に良いフィードバックはありませんでしたので、私はあなたの提案をテストし、あなたが正しいかのように見えます。だから、私はこれを受け入れられた答えとしてマークしています。再び、遅れて申し訳ありません。 –

関連する問題