Использование 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;
}