Проверка узлов xml, а не всего документа
-
23-08-2019 - |
Вопрос
Я работаю с некоторыми xml-"фрагментами", которые формируют элементы в xml.У меня есть схема, но я не могу проверить эти файлы, потому что они не являются полными XML-документами.Эти фрагменты обернуты необходимыми родительскими элементами для формирования допустимого xml-файла при их использовании в других инструментах, поэтому у меня нет особых возможностей преобразовать их в допустимый xml или изменить схему.
Можно ли проверить элемент, а не весь документ?Если нет, то какие обходные пути можно было бы предложить?
Я работаю на C # с .NET 2.0 framework.
Решение
У меня была похожая проблема, когда я мог проверить только части моего 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 (который я выбираю из всего XML-документа с помощью .SelectSingleNode) и XML-схему, которую я загружаю из встроенного ресурса XSD внутри моего приложения.Любые ошибки проверки, которые могут возникнуть, заносятся в конструктор строк "ошибки", который я затем зачитываю в конце, чтобы посмотреть, были ли зафиксированы какие-либо ошибки или нет.
Работает для меня - ваш пробег может отличаться :-)
Другие советы
Существует XmlDocument.Validate
метод, который требует XmlNode
в качестве аргумента an проверяет только этот узел.Возможно , это то , что вы ищете ...
Хорошо, вот другой подход:
Вы могли бы преобразовать свой файл схемы с помощью преобразования 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-документ, содержащий один узел сниппета.
Вы можете использовать специальный псевдоним пространства имен для выделения элементов, которые хотите проверить, а затем добавлять схему только для этого псевдонима пространства имен, но не для других.Таким образом, будут проверены только те элементы с вашим специальным префиксом пространства имен.
Не кажется невозможным сделать то, к чему я стремлюсь.Моя текущая работа заключается в создании пустого шаблона xml-документа.Затем замените нужный элемент моим фрагментом.Исходя из этого, я полагаю, что тогда метод Validate был бы жизнеспособен.Но динамическое создание этого шаблона, по-видимому, само по себе является еще одной сложной задачей.Похоже, что не существует какого-либо простого способа создать документ "скелет".
У меня была такая же проблема.Даже просил здесь решения.Я нашел обходной путь.
Проблема в том, что проверке могут быть подвергнуты только корневые элементы.Итак...Я редактирую схему В ПАМЯТИ и добавляю элемент / тип для проверки в корневой каталог
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-файлы :) С помощью этого простого изменения в вашей схеме в памяти вы можете проверить фрагмент с помощью того же кода, который вы используете для проверки полного документа.Просто убедитесь, что корневой элемент проверяемого фрагмента включает пространство имен.:)