Использование XSD с

Вот XSD:

<?xml version="1.0"?>
<xsd:schema 
elementFormDefault='unqualified' 
attributeFormDefault='unqualified' 
xmlns:xsd='http://www.w3.org/2001/XMLSchema' 
>

  <xsd:simpleType name='TheSimpleType'>
    <xsd:restriction base='xsd:string' />
  </xsd:simpleType>
</xsd:schema>

Вот второй XSD, который включает в себя следующее:

<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema 
elementFormDefault='unqualified' 
attributeFormDefault='unqualified' 
xmlns:xsd='http://www.w3.org/2001/XMLSchema' 
targetNamespace='a'
xmlns='a'
>

  <xsd:include schemaLocation='Include.xsd' />

  <xsd:element name = "TheElement" >
  <xsd:complexType>
  <xsd:attribute name="Code" type="TheSimpleType" use="required"/>
  </xsd:complexType>
  </xsd:element>
</xsd:schema>

Мне нужно прочитать (второй) XSD в С# и:

  • проверьте, что это действительный XSD, и
  • проверить документы против него.

Вот несколько С# для чтения в схемах:

    XmlSchemaSet schemaSet = new XmlSchemaSet();
    foreach (string sd in Schemas)
    {
        using (XmlReader r = XmlReader.Create(new FileStream(sd, FileMode.Open)))
        {
            schemaSet.Add(XmlSchema.Read(r, null));
        }
    }
    schemaSet.CompilationSettings = new XmlSchemaCompilationSettings();
    schemaSet.Compile();

Ошибка .Compile() завершается с ошибкой, потому что "Тип": TheSimpleType 'не объявлен или не является простым типом. "

Однако он работает, если:

  • пространство имен удаляется из схемы или
  • пространство имен добавляется к include.

Вопрос: как мне заставить С# принять его без редактирования схем?

Я подозреваю, что проблема заключается в том, что, хотя я поместил обе схемы в XmlSchemaSet, мне все равно нужно сообщить С#, что один из них включен в другой, то есть он не работал сам по себе. Действительно, если я расскажу только XmlSchemaSet об основном XSD (а не о включении) (оба без (или с) пространствами имен), тогда "Тип" TheSimpleType "не объявлен или не является простым типом".

Таким образом, это, кажется, вопрос о разрешении включает: как?!

Ответы

Ответ 1

Проблема заключается в том, как открывается схема для чтения в строке:

XmlReader.Create(new FileStream(sd, FileMode.Open)

Мне пришлось написать свой собственный XmlResolver, прежде чем я узнал, как разрешаются пути к включенным файлам: он был из каталога исполняемого файла, а не из каталога родительской схемы. Проблема в том, что родительская схема не получала свой набор BaseURI. Здесь, как должна открываться схема:

XmlReader.Create(new FileStream(pathname, FileMode.Open, FileAccess.Read),null, pathname)

Ответ 2

Вы можете использовать XmlSchema.Includes, чтобы связать их вместе. Затем вам просто нужно добавить основную схему к набору схем:

var includeSchema = XmlSchema.Read(XmlReader.Create(...), null);
var mainSchema = XmlSchema.Read(XmlReader.Create(...), null);

var include = new XmlSchemaInclude();
include.Schema = includeSchema;
mainSchema.Includes.Add(include);

var schemaSet = new XmlSchemaSet();
schemaSet.Add(mainSchema);
schemaSet.Compile();

Ответ 3

Попробуйте следующее: D

public static XmlSchema LoadSchema(string pathname)
{
    XmlSchema s = null;
    XmlValidationHandler h = new XmlValidationHandler();
    using (XmlReader r = XmlReader.Create(new FileStream(pathname, FileMode.Open)))
    {
        s = XmlSchema.Read(r, new ValidationEventHandler(h.HandleValidationEvent));
    }

    if (h.Errors.Count > 0)
    {
        throw new Exception(string.Format("There were {1} errors reading the XSD at {0}. The first is: {2}.", pathname, h.Errors.Count, h.Errors[0]));
    }

    return s;
}

public static XmlSchema LoadSchemaAndResolveIncludes(string pathname)
{
    FileInfo f = new FileInfo(pathname);
    XmlSchema s = LoadSchema(f.FullName);

    foreach(XmlSchemaInclude i in s.Includes)
    {
        XmlSchema si = LoadSchema(f.Directory.FullName + @"\" + i.SchemaLocation);
        si.TargetNamespace = s.TargetNamespace;
        i.Schema = si;
    }

    return s;
}

public static List<ValidationEventArgs> Validate(string pathnameDocument, string pathnameSchema)
{
    XmlSchema s = LoadSchemaAndResolveIncludes(pathnameSchema);

    XmlValidationHandler h = new XmlValidationHandler();

    XmlDocument x = new XmlDocument();
    x.Load(pathnameDocument);
    x.Schemas.Add(s);
    s.Compile(new ValidationEventHandler(h.HandleValidationEvent));
    x.Validate(new ValidationEventHandler(h.HandleValidationEvent));
    return h.Errors;
}

Обратите внимание, в частности, на si.TargetNamespace = s.TargetNamespace;.

Очевидно, это предполагает, что включения указаны как пути к файлам относительно схемы, в которую они включены.

Ответ 4

Вот метод, который я написал для обработки проверки xsd. Надеюсь, это поможет кому-то.

        /// <summary>
        /// Ensure all xsd imported xsd documented are in same folder as master xsd
        /// </summary>
        public XsdXmlValidatorResult Validate(string xmlPath, string xsdPath, string xsdNameSpace)
        {
            var result = new XsdXmlValidatorResult();
            var readerSettings = new XmlReaderSettings {ValidationType = ValidationType.Schema};
            readerSettings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema; 
            readerSettings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
            readerSettings.Schemas.Add(null, xsdPath);

            readerSettings.ValidationEventHandler += (sender, args) =>
                {
                    switch (args.Severity)
                    {
                        case XmlSeverityType.Warning:
                            result.Warnings.Add(args.Message);
                            break;
                        case XmlSeverityType.Error:
                            result.IsValid = false;
                            result.Warnings.Add(args.Message);
                            break;
                    }
                };

            var reader = XmlReader.Create(xmlPath, readerSettings);

            while (reader.Read()) { }

            return result;
        }