【发布时间】:2009-03-30 21:07:16
【问题描述】:
描述有点长,请多多包涵。我想处理和验证一个巨大的 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>
我目前能够通过使用带有 XMLReader 的 ValidationEventHandler 来从 XmlSchemaValidationException 中恢复,这会引发我在 XML 处理代码中处理的异常。但是,在某些情况下,会触发 XMLException,这会导致进程终止。
下面的sn-ps代码说明了我当前使用的结构;比较乱,也欢迎提出代码改进建议。
// 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);
}
当遇到 XMLSchemaValidationException 时,finally 块将调用 close() 并且原始 XMLReader 被定位在子树的 EndElement 上,因此 processA 中的 finally 块将导致处理下一个节点 A。
但是,当遇到 XMlException 调用 close 方法时,不会将原始读取器定位在子树的 EndElement 节点上,并且会抛出 InvalidOperationException。
我尝试使用诸如 skip、ReadToXYZ() 方法之类的方法,但是当在任何触发异常的节点上调用时,这些方法总是会导致 XMLExcpetion 的 InvalidOperationException。
以下是 MSDN 关于 ReadSubTree 方法的摘录。
当新的 XmlReader 已经 关闭,原来的 XmlReader 将 位于的 EndElement 节点上 子树。因此,如果您调用 开始标签上的 ReadSubtree 方法 book 元素,在子树之后 已阅读和新的 XmlReader 已关闭,原 XmlReader 位于结束标记上 book 元素。
注意:我不能为此使用 .Net 3.5,但是欢迎 .Net 3.5 建议。
【问题讨论】: