Описание немного длиннее, пожалуйста, потерпите меня. Я хотел бы обработать и проверить огромный XML-файл и зарегистрировать узел, который вызвал ошибку проверки, и продолжить обработку следующего узла. Упрощенная версия файла XML показана ниже.
То, что я хотел бы выполнить, - это встретить любой узел обработки ошибок валидации 'A' или его дочерние элементы (как XMLException, так и XmlSchemaValidationException). Я хотел бы прекратить обработку журнала текущего узла, ошибки и XML для узла 'A' и перейти к следующему узлу '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>
В настоящее время я могу выполнить восстановление из XmlSchemaValidationException с помощью ValidationEventHandler с XMLReader, который выдает исключение, которое я обрабатываю, в коде обработки XML. Однако в некоторых случаях запускается 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);
}
Когда встречается исключение XMLSchemaValidationException, блок finally будет вызывать close (), и исходный XMLReader позиционируется на EndElement поддерева, и, следовательно, блок finally в processA приведет к обработке следующего узла A.
Однако, когда XMlException встречается, вызывая метод close, он не позиционирует исходный читатель на узле EndElement поддерева, и генерируется исключение InvalidOperationException.
Я пытался использовать такие методы, как skip, ReadToXYZ (), но они неизменно приводят к XMLExcpetion InvalidOperationException при вызове на любом узле, вызвавшем исключение.
Ниже приводится выдержка из MSDN относительно метода ReadSubTree.
Когда новый XmlReader был
закрыто, оригинальный XmlReader будет
расположенный на узле EndElement
поддерево. Таким образом, если вы назвали
Метод ReadSubtree для начального тега
элемент книги, после поддерева
был прочитан и новый XmlReader
был закрыт, оригинал
XmlReader располагается на конце тега
элемента книги.
Примечание. Я не могу использовать .Net 3.5 для этого, однако приветствуются предложения .Net 3.5.