Проверка XML с помощью XSD - PullRequest
7 голосов
/ 03 июня 2009

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

Я сузил свою задачу до простого примера Windows Forms приложения. Он имеет текстовое поле для XSD (txtXsd), текстовое поле для XML (txtXml), текстовое поле для результата (txtResult) и кнопку для запуска проверки (btnValidate).

Я использую образец XSD-файла от Microsoft,

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn:bookstore-schema" elementFormDefault="qualified" targetNamespace="urn:bookstore-schema">
    <xsd:element name="title" type="xsd:string" />
    <xsd:element name="comment" type="xsd:string" />
    <xsd:element name="author" type="authorName"/>
    <xsd:complexType name="authorName">
        <xsd:sequence>
            <xsd:element name="first-name" type="xsd:string" />
            <xsd:element name="last-name" type="xsd:string" />
        </xsd:sequence>
    </xsd:complexType>
</xsd:schema>

Я использую следующий код в своем приложении.

private void btnValidate_Click (object sender, EventArgs e)
{
    try
    {
        XmlTextReader reader = new XmlTextReader(txtXsd.Text, XmlNodeType.Document, new XmlParserContext(null, null, String.Empty, XmlSpace.None));
        XmlSchema schema = XmlSchema.Read(reader, null);
        XmlSchemaSet schemas = new XmlSchemaSet();
        schemas.Add(schema);

        XDocument doc = XDocument.Parse(txtXml.Text);
        doc.Validate(schemas, ValidateSchema);
    }
    catch (Exception exception)
    {
        txtResult.Text += exception.Message + Environment.NewLine;
    }
}

private void ValidateSchema (Object sender, ValidationEventArgs e)
{
    txtResult.Text += e.Message + Environment.NewLine;
}

В качестве теста я вставил действительный XML, но то, что я считаю, не должно соответствовать приведенному выше XSD.

<xml>
    <bogusNode>blah</bogusNode>
</xml>

Результат - ничто, никаких ошибок валидации. Как мне это исправить?

Ответы [ 3 ]

4 голосов
/ 03 июня 2009

Ну, во-первых, ваш XSD определяет пространство имен XML xmlns="urn:bookstore-schema", которого нет в вашем тестовом XML-файле - следовательно, ничего в вашем тестовом XML-файле не будет проверено.

Если вы удалите эти элементы, сформируйте схему:

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <xsd:element name="title" type="xsd:string" />

тогда он правильно проверит ваш тестовый XML-файл и пожалуется на неправильные элементы.

Также использование элемента с именем <xml> может быть не очень хорошей идеей, поскольку директива <?xml ......?> является предопределенной директивой и не должна появляться в качестве имени тега в другом месте документа.

Марк

2 голосов
/ 03 июня 2009

Я не хочу, чтобы пользователь отправлял XML, который не определен в XSD.

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

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

    public static void Main()
    {
        const string myNamespaceURN = "urn:my-namespace";

        XmlSchemaSet sc = new XmlSchemaSet();
        sc.Add(myNamespaceURN, "mySchema.xsd");

        XmlReaderSettings settings = new XmlReaderSettings();
        settings.ValidationType = ValidationType.Schema;
        settings.Schemas = sc;
        settings.ValidationEventHandler += ValidationCallBack;

        XmlReader reader = XmlReader.Create("myDocument.xml", settings);

        while (reader.Read())
        {
            if ((reader.NodeType == XmlNodeType.Element ||
                 reader.NodeType == XmlNodeType.Attribute)
                &&
                reader.NamespaceURI != myNamespaceURN)
            {
                LogError(reader.NamespaceURI + " is not a valid namespace.");
            }
        }
    }

    private static void ValidationCallBack(object sender, ValidationEventArgs e)
    {
        LogError(e.Message);
    }

    private static void LogError(string msg)
    {
        Console.WriteLine(msg);
    }
1 голос
/ 03 июня 2009

Вы также можете попробовать XmlValidatingReader для проверки XML

...