2009-03-30 5 views
3

説明は長い方が少しわかります。私は巨大なXMLファイルを処理し検証し、検証エラーを引き起こしたノードを記録し、次のノードの処理を続行したいと思います。 XMLファイルの簡略版を以下に示します。C#のXMLファイルの検証エラーを正常に処理します

ノード 'A'またはその子(XMLExceptionとXmlSchemaValidationExceptionの両方)を処理している検証エラーが発生しました。現在のノードの処理を停止します。ノード 'A'のエラーとXMLを記録して移動します。次のノード「A」へ進む。

<Root> 
    <A id="A1"> 
    <B Name="B1"> 
     <C> 
      <D Name="ID" > 
      <E>Test Text 1</E> 
      </D> 
     <D Name="text" > 
      <E>Test Text 1</E> 
     </D>   
     </C> 
    </B> 
    </A> 
    <A id="A2"> 
    <B Name="B2"> 
     <C> 
     <D Name="id" > 
      <E>Test Text 3</E> 
     </D> 
     <D Name="tab1_id" > 
      <E>Test Text 3</E> 
     </D> 
     <D Name="text" > 
      <E>Test Text 3</E> 
     </D> 
     </C> 
    </B> 
</Root> 

は、私は現在、私はXML処理コードで扱う例外をスローしたXMLReaderとのValidationEventHandlerを使用してXmlSchemaValidationExceptionから回復することができています。しかし、場合によってはXMLExceptionがトリガーされているため、プロセスが終了することがあります。

コードの次のスニペットは、私が使用している現在の構造を示しています。それは面倒であり、コード改善の提案も歓迎です。 XMLSchemaValidationExceptionが検出されると

// Setting up the XMLReader 
    XmlReaderSettings settings = new XmlReaderSettings(); 
    settings.ConformanceLevel = ConformanceLevel.Auto; 
    settings.IgnoreWhitespace = true; 
    settings.CloseInput = true; 
    settings.IgnoreComments = true; 
    settings.ValidationType = ValidationType.Schema; 
    settings.Schemas.Add(null, "schema.xsd"); 
    settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack); 
    XmlReader reader = XmlReader.Create("Sample.xml", settings); 
    // Processing XML 
    while (reader.Read()) 
    if (reader.NodeType == XmlNodeType.Element) 
     if (reader.Name.Equals("A")) 
     processA(reader.ReadSubtree());    
    reader.Close(); 
    // Process Node A 
    private static void processA(XmlReader A){ 
    try{ 
     // Perform some book-keeping 
     // Process Node B by calling processB(A.ReadSubTree())    
    } 
    catch (InvalidOperationException ex){ 

    } 
    catch (XmlException xmlEx){ 

    } 
    catch (ImportException impEx){ 

    } 
    finally{ if (A != null) A.Close(); }    
    } 
    // All the lower level process node functions propagate the exception to caller. 
    private static void processB(XmlReader B){ 
    try{ 
    // Book-keeping and call processC 
    } 
    catch (Exception ex){ 
    throw ex; 
    } 
    finally{ if (B != null) B.Close();}  
    } 
    // Validation event handler 
    private static void ValidationCallBack(object sender, ValidationEventArgs e){ 
    String msg = "Validation Error: " + e.Message +" at line " + e.Exception.LineNumber+ 
     " position number "+e.Exception.LinePosition; 
    throw new ImportException(msg); 
    } 

finallyブロックは、(近い起動する)と、元のXMLReaderがサブツリーの上に位置するendElement、したがって最終的processAにブロックされている次のノードAの処理につながります

ただし、XMlExceptionが発生した場合、closeメソッドを呼び出すと、元のリーダーがサブツリーのEndElementノードに配置されず、InvalidOperationExceptionがスローされます。

私はスキップ、ReadToXYZ()メソッドのようなメソッドを使用しようとしましたが、これらは例外をトリガーしたノードで呼び出されたとき必ずInvalidOperationExceptionのXMLExcpetionにつながります。

以下は、ReadSubTreeメソッドに関するMSDNの抜粋です。新しいXMLReaderが が閉じられた場合

、オリジナルXMLReaderが サブツリーのするendElementノード上に配置 あろう。あなたは book要素の開始タグに ReadSubtreeメソッドを呼び出した場合はこのように、読まれていて、新しいXmlReaderの が閉じられた サブツリー後、元 たXmlReaderはの終了タグ 上に配置されていますブック要素。

注:これは.Net 3.5を使用できませんが、.Net 3.5の提案は大歓迎です。

答えて

5

この質問を参照してください:あなたは整形 XML(それが本当のxmlである必要はルールに従う)と有効 XMLは(特定によって与えられた追加のルールに従って区別する必要が
XML Parser Validation Report

をxmlスキーマ)。仕様から:

しかし、致命的なエラーが検出されると、プロセッサは通常の処理を続行してはいけません(つまり、文字データとドキュメントの論理構造に関する情報を引き続き通常の方法)。

は、良くも悪くも、XMLツールは、整形式エラーがある場合は処理を続行されませんので、非常に密接にそのスペックを実行する必要があり、およびVisual Studioに含まれています。私が提供したリンクはあなたにいくつかの選択肢を与えるかもしれません。

2

私は例外食べると疑問使用XmlReader.Close()を除いて、ほとんどあなたが持っているように、これを行っている:

XmlReaderSettings settings = new XmlReaderSettings(); 
settings.ConformanceLevel = ConformanceLevel.Auto; 
settings.IgnoreWhitespace = true; 
settings.CloseInput = true; 
settings.IgnoreComments = true; 
settings.ValidationType = ValidationType.Schema; 
settings.Schemas.Add(null, "schema.xsd"); 
settings.ValidationEventHandler += ValidationCallBack; 
using (XmlReader reader = XmlReader.Create("Sample.xml", settings)) 
{ 
    while (reader.Read()) 
    { 
     if (reader.NodeType == XmlNodeType.Element && 
      reader.Name.Equals("A")) 
     { 
      using (
       XmlReader subtree = reader.ReadSubtree()) 
      { 
       try { 
        processA(subtree); 
       } 
       catch (ImportException ex) { // log it at least } 
       catch (XmlException ex) {// log this too } 
       // I would not catch InvalidOperationException - too general 
      } 
     } 
    } 
} 

private static void processA(XmlReader A) 
{ 
    using (XmlReader subtree = A.ReadSubtree()) 
    { 
     processB(subtree); 
    } 
} 

// All the lower level process node functions propagate the exception to caller. 
private static void processB(XmlReader B) 
{ 
} 

あなたはprocessAからのものを除き、例外を食べにしたくありません。 processAの呼び出し側が例外を無視することを決定させます - processAはそれを認識すべきではありません。 と同じです。ブロックを使用してください - 内側ではなく外側に置いてください。

+0

例外を処理して、コードを簡潔にするためにコードを削除しました。私は最終的にブロックで他のいくつかのアクションを実行する必要があるので、私は "使用"ブロックを使用する利点を見た。 – welllifeisunfair

関連する問題