xsd: импорт внутри встроенного ресурса XSD - PullRequest
4 голосов
/ 17 марта 2011

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

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

Редактировать - Обновить

Я реализовал предложение Александра ниже, но, как я отмечал в своем комментарии, всякий раз, когда GetEntity() вызывается для xs:import 'd XSD, ofObjectToReturn равен null. Это заставило первый экземпляр типа xs:import создать исключение «тип не определен».

Чтобы решить эту проблему, я изменил GetEntity(), чтобы он возвращал GetManifestResourceStream() независимо от значения ofObjectToReturn. Похоже, что теперь это работает для первого уровня операторов xs:import, но дополнительный xs:import внутри одного из оригинальных xs:import XSD не работает. Я подтвердил, что GetEntity() вызывается для этого вторичного xs:import, но я получаю исключение "тип не определен" для типа, определенного в этом вторичном XSD.

  • TopLevel.xsd - типы разрешают в порядке
    • FirstLevelImport1.xsd - типы разрешаются в порядке
    • FirstLevelImport2.xsd - типы разрешаются в порядке
      • SecondLevelImport1.xsd - Исключение "тип не определен" для типа, определенного в этом XSD

Исключение «тип не определен» выдается во время XmlReader.Create(), которому передано XmlReaderSettings, определяющее проверку схемы.

Ответы [ 2 ]

5 голосов
/ 17 марта 2011

Для разрешения файлов, которые добавляются либо xsd:import, либо xsd:include, вы можете использовать пользовательский XmlResolver .Вы можете найти пример ResourceXmlResolver ниже.Предполагается, что имя сборки " AYez.EmbeddedXsdTests ".

using System.Xml;
using System.Xml.Schema;
using NUnit.Framework;

namespace AYez.EmbeddedXsdTests
{
    [TestFixture]
    public class EmbeddedXsdTests
    {
        [Test]
        public void SomeEntryPoint()
        {
            var schemaSet = new XmlSchemaSet {XmlResolver = new ResourceXmlResolver()};
            schemaSet.Add("rrn:org.xcbl:schemas/xcbl/v4_0/financial/v1_0/financial.xsd", @"Invoice.xsd");
            schemaSet.Compile();

            var settings = new XmlReaderSettings { ValidationType = ValidationType.Schema, Schemas = schemaSet };

            settings.ValidationEventHandler += delegate(object o, ValidationEventArgs e)
            {
                switch (e.Severity)
                {
                    case XmlSeverityType.Error:
                        Console.Write("Error: {0}", e.Message);
                        break;
                    case XmlSeverityType.Warning:
                        Console.Write("Warning: {0}", e.Message);
                        break;
                }
            };
            var xmlReader = XmlReader.Create(@"d:\temp\Invoice.xml", settings);
            while (xmlReader.Read()) { /*TODO: Nothing*/} // Validation is performed while reading

        }
    }

    public class ResourceXmlResolver: XmlResolver
    {
        /// <summary>
        /// When overridden in a derived class, maps a URI to an object containing the actual resource.
        /// </summary>
        /// <returns>
        /// A System.IO.Stream object or null if a type other than stream is specified.
        /// </returns>
        /// <param name="absoluteUri">The URI returned from <see cref="M:System.Xml.XmlResolver.ResolveUri(System.Uri,System.String)"/>. </param><param name="role">The current version does not use this parameter when resolving URIs. This is provided for future extensibility purposes. For example, this can be mapped to the xlink:role and used as an implementation specific argument in other scenarios. </param><param name="ofObjectToReturn">The type of object to return. The current version only returns System.IO.Stream objects. </param><exception cref="T:System.Xml.XmlException"><paramref name="ofObjectToReturn"/> is not a Stream type. </exception><exception cref="T:System.UriFormatException">The specified URI is not an absolute URI. </exception><exception cref="T:System.ArgumentNullException"><paramref name="absoluteUri"/> is null. </exception><exception cref="T:System.Exception">There is a runtime error (for example, an interrupted server connection). </exception>
        public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)
        {   
                // If ofObjectToReturn is null, then any of the following types can be returned for correct processing:
                // Stream, TextReader, XmlReader or descendants of XmlSchema
                var result =  this.GetType().Assembly.GetManifestResourceStream(string.Format("AYez.EmbeddedXsdTests.{0}",
                                                                                             Path.GetFileName(absoluteUri.ToString())));                
                // set a conditional breakpoint "result==null" here
                return result;
        }

        /// <summary>
        /// When overridden in a derived class, sets the credentials used to authenticate Web requests.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.Net.ICredentials"/> object. If this property is not set, the value defaults to null; that is, the XmlResolver has no user credentials.
        /// </returns>
        public override ICredentials Credentials
        {
            set { throw new NotImplementedException(); }
        }
    }
}
2 голосов
/ 14 декабря 2011

Проблема может быть решена, если мы сначала прочитаем файлы xsd в строковую переменную.

, например

var stream =assembly.GetManifestResourceStream("Namespace.child.xsd");

теперь используйте потоковый ридер, чтобы прочитать это в строку

, например

string childXSD=new StreamReader(stream).ReadToEnd();

similary get string ParentXSD Тогда используйте

var xmlReader=XmlReader.Create(new MemoryStream(Encoding.Default.GetBytes(childXSD)));
schemaCollection.Add(null,xmlReader);
var xmlReader=XmlReader.Create(new MemoryStream(Encoding.Default.GetBytes(parentXSD)));
schemaCollection.Add(null,xmlReader);

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

...