Компиляция схемы, содержащей переопределения на C#

#c# #xml #include #schema #redefinition

#c# #xml #включить #схема #переопределение

Вопрос:

При чтении схемы, содержащей <xs:redefine> теги, и попытке ее компиляции с использованием набора схем я получаю это исключение:

 'SchemaLocation' must successfully resolve if <redefine>
contains any child other than <annotation>
  

Я безуспешно пробовал множество обходных путей, таких как рекурсивный анализ схем и добавление их в набор схем перед компиляцией и даже путем добавления их в качестве ссылки. Тем не менее, схема не компилируется. Пример того, что было опробовано (анализ основного xsd, а затем попытка скомпилировать результирующие «XmlSchemas» после вызова этой рекурсивной функции):

 private void AddRecursive (XmlSchemas xsds, XmlSchema schema)
{
    foreach (XmlSchemaExternal inc in schema.Includes) {
        String schemaLocation = null;
        schemaLocation = inc.SchemaLocation;
        XmlSchema xsd;
        using (FileStream stream = new FileStream (schemaLocation, FileMode.Open, FileAccess.Read)) {
            xsd = XmlSchema.Read (stream, null);
            xsds.Add (xsd);
            xsds.AddReference (xsd);
        }
        AddRecursive (xsds, xsd);
    }
}
  

Каков правильный способ обработки таких схем? Почему компилятор схемы не может разрешить добавленные схемы самостоятельно?

Ответ №1:

Проблема с чтением XML-схемы с использованием потоковой перегрузки заключается в том, что нет базового uri, доступного для чтения XML-схемы. Если ваш xsd:redefine использует относительный URI в атрибуте schemaLocation, распознаватель по умолчанию не сможет найти переопределяемую схему — отсюда и сообщение об ошибке, которое вы получаете.

Я предоставляю вам следующую конфигурацию, чтобы вы могли начать, по крайней мере, понять, как это работает. Сохраните две схемы и тестовый сценарий в одной папке, обновите пути в сценарии и запустите сценарий C #. Это даст вам такой результат:

 QN: http://tempuri.org/XMLSchema.xsd:TRedefine, SourceUri: file:///D:/.../.../Redefine.xsd
QN: http://www.w3.org/2001/XMLSchema:anyType, SourceUri: 
  

Если вы обновите скрипт для использования перегрузки на основе потока, вы получите сообщение об ошибке из вашего post.

 Error line 20:      xset.Add(XmlSchema.Read(File.Open    (@"D:......Redefine.xsd", FileMode.Open), null));
    'SchemaLocation' must successfully resolve if <redefine> contains any child other than     <annotation>.
'SchemaLocation' must successfully resolve if <redefine> contains any child other than     <annotation>.
Error Line 21: xset.Add(XmlSchema.Read(File.Open    (@"D:......Redefine.xsd", FileMode.Open), null));
  

Базовая схема:

 <?xml version="1.0" encoding="utf-8" ?>
<xsd:schema targetNamespace="http://tempuri.org/XMLSchema.xsd"
    elementFormDefault="qualified"
    xmlns="http://tempuri.org/XMLSchema.xsd"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:complexType name="TRedefine">
        <xsd:sequence>
            <xsd:element name="base" type="xsd:string"/>
        </xsd:sequence>
    </xsd:complexType>
</xsd:schema>
  

Схема, которая переопределяет:

 <?xml version="1.0" encoding="utf-8"?>
<!--XML Schema generated by QTAssistant/XSR Module (http://www.paschidev.com)-->
<xsd:schema xmlns="http://tempuri.org/XMLSchema.xsd" attributeFormDefault="unqualified"     elementFormDefault="qualified" targetNamespace="http://tempuri.org/XMLSchema.xsd"     xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <!-- Put a full path here.
  <xsd:redefine schemaLocation="D:......Base.xsd">
    -->
    <xsd:redefine schemaLocation="Base.xsd">
        <xsd:complexType name="TRedefine">
            <xsd:complexContent>
                <xsd:extension base="TRedefine">
                    <xsd:sequence/>
                </xsd:extension>
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:redefine>
</xsd:schema>
  

Тестовый сценарий:

 using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
class Script
{
    public static void Main()
    {
        // Enter your code below
        // Generated by QTAssistant (http://www.paschidev.com)
        XmlSchemaSet xset = new XmlSchemaSet();

        // One way of doing using an XmlReader - it'll work with relative URIs.
        using(XmlReader reader = XmlReader.Create(@"D:......Redefine.xsd"))
        {
            xset.Add(XmlSchema.Read(reader, null));
        }

        // The other way, using stream, requires all external URIs - xsd:include,     xsd:import and xsd:redefine 
        // to be absolute
        //xset.Add(XmlSchema.Read(File.Open(@"D:......Redefine.xsd", FileMode.Open), null));

        xset.Compile();
        Console.WriteLine(xset.IsCompiled);
        foreach(XmlSchemaType type in xset.GlobalTypes.Values) 
        {
            Console.WriteLine("QN: {0}, SourceUri: {1}", type.QualifiedName,     type.SourceUri);
        }
    }
}
  

Комментарии:

1. Большое спасибо, действительно так просто! Я XmlSchemas все время переключался, чтобы XmlSchemaSet решить проблему.

Ответ №2:

Рабочий пример с родственными путями с помощью XmlDocument:

         XmlReaderSettings settings = new XmlReaderSettings();
        settings.ValidationType = ValidationType.Schema;
        // It won't add schemas without XmlUrlResolver
        settings.Schemas.XmlResolver = new XmlUrlResolver();
        // Optional namespace
        var namespace = null;
        settings.Schemas.Add(namespace, "absolutePath.xsd");

        using (XmlReader reader = XmlReader.Create(sourcePath, settings))
        {
            XmlDocument document= new XmlDocument();
            document.Load(reader);
            //...
        }
  

Комментарии:

1. Добавление a new XmlUrlResolver() сработало для меня!