Проверка узлов XML, а не всего документа - PullRequest
4 голосов
/ 04 апреля 2009

Я работаю с некоторыми «фрагментами» XML, которые формируют элементы в XML. У меня есть схема, но я не могу проверить эти файлы, потому что они не являются полными XML-документами. Эти фрагменты обернуты необходимыми родительскими элементами, чтобы сформировать действительный xml, когда они используются в других инструментах, поэтому у меня нет особого выбора превратить их в действительный xml или изменить схему.

Можно ли проверить элемент, а не весь документ? Если нет, какие обходные пути могут быть предложены?

Я работаю в C # с .NET 2.0 framework.

Ответы [ 6 ]

4 голосов
/ 08 апреля 2009

У меня была похожая проблема, когда я мог проверять только части своего XML-документа. Я придумал этот метод здесь:

private void ValidateSubnode(XmlNode node, XmlSchema schema)
{
    XmlTextReader reader = new XmlTextReader(node.OuterXml, XmlNodeType.Element, null);

    XmlReaderSettings settings = new XmlReaderSettings();
    settings.ConformanceLevel = ConformanceLevel.Fragment;
    settings.Schemas.Add(schema);
    settings.ValidationType = ValidationType.Schema;
    settings.ValidationEventHandler += new ValidationEventHandler(XSDValidationEventHandler);

    using (XmlReader validationReader = XmlReader.Create(reader, settings))
    {     
        while (validationReader.Read())
        {
        }
    }
}

private void XSDValidationEventHandler(object sender, ValidationEventArgs args)
{
    errors.AppendFormat("XSD - Severity {0} - {1}", 
                        args.Severity.ToString(), args.Message);
}

По сути, я передаю ему XmlNode (который я выбираю из всего XmlDocument с помощью .SelectSingleNode) и XML-схему, которую я загружаю из встроенного ресурса XSD внутри моего приложения. Любые ошибки проверки, которые могут возникнуть, помещаются в конструктор строк «ошибки», который я затем зачитываю в конце, чтобы посмотреть, были ли записаны какие-либо ошибки или нет.

У меня работает - ваш пробег может варьироваться: -)

2 голосов
/ 04 апреля 2009

Существует метод XmlDocument.Validate, который принимает XmlNode в качестве аргумента и проверяет только этот узел. Это может быть то, что вы ищете ...

1 голос
/ 07 апреля 2009

Хорошо, вот другой подход:

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

<xs:schema id="MySchema" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="RootElement">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="NestedElement">
          <xs:complexType>
            <xs:attribute name="Name" type="xs:string" use="required"/>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

У вас есть фрагменты типа NestedElement, которые вы хотите проверить:

<NestedElement Name1="Name1" />

Тогда вы можете использовать шаблон XSLT, такой как

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="xs:element[@name='NestedElement']"
                xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:schema id="MySchema">
      <xsl:copy-of select="."/>
    </xs:schema>
  </xsl:template>
</xsl:stylesheet>

Для создания новой схемы с NestedElement в качестве пользователя root. Результирующая схема будет выглядеть как

<xs:schema id="MySchema" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="NestedElement">
    <xs:complexType>
      <xs:attribute name="Name" type="xs:string" use="required" />
    </xs:complexType>
  </xs:element>
</xs:schema>

Затем вы можете проверить документ фрагмента по этой новой схеме, используя код, подобный

XmlSchema schema;
using (MemoryStream stream =    new MemoryStream())
using (FileStream fs = new FileStream("MySchema.xsd", FileMode.Open))
using(XmlReader reader = XmlReader.Create(fs)) {
  XslCompiledTransform transform = new XslCompiledTransform();
  transform.Load("SchemaTransform.xslt");
  transform.Transform(reader, null, stream);
  stream.Seek(0, SeekOrigin.Begin);
  schema = XmlSchema.Read(stream, null);
}
XmlDocument doc = new XmlDocument();
doc.Schemas.Add(schema);
doc.Load("rootelement.xml");
doc.Validate(ValidationHandler);

MySchema.xsd - исходная схема, SchemaTransform.xslt - преобразование (как показано выше), rootelement.xml - документ XML, содержащий один узел фрагмента.

0 голосов
/ 10 октября 2013

У меня была такая же проблема. Даже спросил здесь для решения. Я нашел обходной путь.

Проблема в том, что только корневые элементы могут быть проверены. Итак ... я редактирую схему IN MEMORY и добавляю элемент / тип для проверки в корень

public static void AddElementToSchema(XmlSchema xmlSchema, string elementName, string elementType, string xmlNamespace)
{
    XmlSchemaElement testNode = new XmlSchemaElement();
    testNode.Name = elementName;
    testNode.Namespaces.Add("", xmlNamespace);
    testNode.SchemaTypeName = new XmlQualifiedName(elementType, xmlNamespace);
    xmlSchema.Items.Add(testNode);
    xmlSchema.Compile(XMLValidationEventHandler);
}

Всего пара строк, и вы не должны изменять или добавлять какие-либо XSD-файлы :). С помощью этого простого изменения вашей схемы в памяти вы можете проверить фрагмент с помощью того же кода, который вы использовали для проверки полного документа. Просто убедитесь, что корневой элемент проверяемого фрагмента включает пространство имен. :)

0 голосов
/ 07 апреля 2009

Не представляется возможным сделать то, что я стремлюсь сделать. Моя текущая работа заключается в создании пустого шаблона XML-документа. Затем замените нужный элемент моим фрагментом. Оттуда, я полагаю, метод Validate был бы жизнеспособным. Но создать этот шаблон динамически, кажется, еще одна сложная задача сама по себе. Кажется, нет простого способа создать «скелетный» документ.

0 голосов
/ 04 апреля 2009

Вы можете использовать специальный псевдоним пространства имен для выделения элементов, которые вы хотите проверить, и затем добавлять схему только для этого псевдонима пространства имен, но не для других. Таким образом, будут проверяться только те элементы с вашим специальным префиксом пространства имен.

...