在C#中优雅地处理XML文件中的验证错误

wel*_*air 3 .net c# xml

描述有点长,请耐心等待.我想处理并验证一个巨大的XML文件,并记录触发验证错误的节点并继续处理下一个节点.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>
Run Code Online (Sandbox Code Playgroud)

我目前能够通过使用带有XMLReader的ValidationEventHandler从XmlSchemaValidationException中恢复,这会抛出我在XML Processing代码中处理的Exception.但是在某些情况下,触发XMLException会导致进程终止.

以下代码片段说明了我正在使用的当前结构; 它很混乱,也欢迎代码改进建议.

    // 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);
  }
Run Code Online (Sandbox Code Playgroud)

遇到XMLSchemaValidationException时,finally块将调用close(),并且原始XMLReader位于子树的EndElement上,因此processA中的finally块将导致处理下一个节点A.

但是,遇到XMlException时,调用close方法不会将原始读取器放在子树的EndElement节点上,而是抛出InvalidOperationException.

我尝试使用诸如skip,ReadToXYZ()方法之类的方法,但是当在触发异常的任何节点上调用时,这些方法总是导致InvalidOperationException的XMLExcpetion.

以下是MSDN关于ReadSubTree方法的摘录.

关闭新的XmlReader后,原始XmlReader将位于子树的EndElement节点上.因此,如果在book元素的start标记上调用ReadSubtree方法,则在读取子树并关闭新的XmlReader之后,原始XmlReader将位于book元素的结束标记上.

注意:我不能使用.Net 3.5,但欢迎.Net 3.5建议.

Joe*_*orn 5

请参阅此问题:
XML分析器验证报告

您需要区分格式良好的 xml(它遵循实际xml所需的规则)和有效的 xml(遵循特定xml架构给出的附加规则).从规格:

但是,一旦检测到致命错误,处理器就不能继续正常处理(即,它不能继续以正常方式将字符数据和有关文档逻辑结构的信息传递给应用程序).

无论好坏,Visual Studio附带的xml工具都需要非常密切地遵循该规范,因此如果存在格式错误,则不会继续处理.我提供的链接可能会为您提供一些替代方案.