Однопроходное чтение и проверка XML по сравнению с XSD со ссылкой в ​​C # - PullRequest
0 голосов
/ 21 марта 2012

Я пытаюсь прочитать данные из файла XML, сверяя их с предлагаемым XSD, в единую структуру данных (например, XmlDocument). У меня есть решение, но оно требует 2 прохода через файл, и мне интересно, есть ли однопроходное решение.

MyBooks.xml:

<Books xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
     xsi:noNamespaceSchemaLocation='books.xsd' id='999'>
    <Book>Book A</Book>
    <Book>Book B</Book>
</Books>

Books.xsd:

<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'
    elementFormDefault='qualified'
    attributeFormDefault='unqualified'>
    <xs:element name='Books'>
        <xs:complexType>
            <xs:sequence>
                <xs:element name='Book' type='xs:string' />
            </xs:sequence>
            <xs:attribute name='id' type='xs:unsignedShort' use='required' />
        </xs:complexType>
    </xs:element>
</xs:schema>

Допустим, MyBooks.xml и Books.xsd находятся в одном каталоге.

Проверка:

//Given a filename pointing to the XML file
var settings = new XmlReaderSettings();

settings.ValidationType = ValidationType.Schema;

settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;

settings.CloseInput = true;
settings.ValidationEventHandler += new ValidationEventHandler(ValidationCB);
//eg:
//private static void ValidationCB(object sender, ValidationEventArgs args)
//{ throw new ApplicationException(args.Message); }

using(var reader = XmlReader.Create(filename, settings))
{ while(reader.Read()) ; }

Читать в XmlDocument:

XmlDocument x = new XmlDocument();
x.Load(filename);

Конечно, я мог бы собирать узлы во время чтения из XmlReader, но я бы предпочел не делать это сам, если это возможно. Любое предложение?

Заранее спасибо

1 Ответ

1 голос
/ 22 марта 2012

Вы очень близки с вашим решением; что вам нужно сделать, это использовать проверяющий читатель для загрузки вашего XML; таким образом, проверка выполняется с вашей загрузкой за один проход; ошибки проверки не остановят вас от загрузки документа.

Это шаги высокого уровня, которые я обычно использую с вспомогательной функцией ValidateXml; все начинается с скомпилированного XmlSchemaSet:

public bool ValidateXml(XmlSchemaSet xset)

Я установил настройки ридера (что вы тоже сделали):

XmlReaderSettings settings = new XmlReaderSettings { ValidationType = ValidationType.Schema, Schemas = xset, ConformanceLevel = ConformanceLevel.Document };
settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
// Use your helper class that collects validation events. 
XsdUtils.Utils.SmartValidationHandler svh = new XsdUtils.Utils.SmartValidationHandler(Paschi.Xml.DefaultResolver.Instance);
settings.ValidationEventHandler += svh.ValidationCallbackOne;

Тогда я получаю читателя:

XmlReader xvr = XmlReader.Create(filename, settings);

Затем я читаю файл, который приносит проверку в:

XmlDocument xdoc = new XmlDocument();
xdoc.Load(xvr);

Ваш обработчик проверки имеет результаты; я также хочу убедиться, что загруженный элемент документа действительно имеет соответствующее глобальное определение элемента в наборе схем xml.

XmlQualifiedName qn = XmlQualifiedName.Empty;
if (xdoc.DocumentElement != null)
{
        if (string.IsNullOrEmpty(xdoc.DocumentElement.NamespaceURI))
        {
              qn = new XmlQualifiedName(xdoc.DocumentElement.LocalName);
        }
        else
        {
               qn = new XmlQualifiedName(xdoc.DocumentElement.LocalName, xdoc.DocumentElement.NamespaceURI);
         }
}
return !(svh.HasError || qn.IsEmpty || (!xset.GlobalElements.Contains(qn)));
...