Компилировать схемы с включенными файлами xsd

92
11

У меня есть статический метод, который я использую для проверки файла XML на файл XSD. Это прекрасно работает, пока не появится файл XSD, который включает в себя другой файл XSD.


Пример, когда у меня возникли проблемы:


TYPES.XSD:


<xs:simpleType name="MY_AMOUNT">
<xs:restriction base="xs:decimal">
<xs:maxInclusive value="999999999999.99"/>
<xs:minInclusive value="-999999999999.99"/>
<xs:totalDigits value="14"/>
<xs:fractionDigits value="2"/>
</xs:restriction>
</xs:simpleType>

MAIN.XSD:


<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:include schemaLocation="TYPES.xsd"/>
<xs:element name="ROOT">
<xs:complexType>
<xs:sequence>
<xs:element ref="SOMEREF1"/>
<xs:element ref="SOMEREF2"/>
<xs:element name="AMOUNT" type="MY_AMOUNT" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

КОД VALIDATION:


public static class XmlUtils
{
private static string Errors = string.Empty;

public static bool ValidateAgainstXSD(string xmlFilePath, string xsdFilePath, ref string message)
{
try
{
var settings = new XmlReaderSettings();

settings.ValidationType = ValidationType.Schema;
settings.ValidationFlags = XmlSchemaValidationFlags.ProcessInlineSchema
| XmlSchemaValidationFlags.ProcessInlineSchema
| XmlSchemaValidationFlags.ReportValidationWarnings;
settings.Schemas.Add(null, xsdFilePath);
settings.Schemas.Compile();

settings.ValidationEventHandler += (sender, args) =>
{
if (args.Severity == XmlSeverityType.Error)
{
Errors += args.Message + "\n";
}
};

using (var reader = XmlReader.Create(xmlFilePath, settings))
{
while (reader.Read()) { }
}

message = Errors ?? string.Empty;
return string.IsNullOrEmpty(Errors);
}
catch (Exception e)
{
message = "# error validating xml file: " + e.Message;
return false;
}
}
}


Как-то кажется, что я должен указать путь к включенному XSD файлу, но я понятия не имею, где.


Ошибка возникает при settings.Schemas.Compile();, где указано, что тип "MY_AMOUNT" не объявлен. Я читал о пользовательских XmlResolvers, но, честно говоря, я не получил этого.


Если это важно для ответа: файлы xsd всегда находятся в одном каталоге!


Метод называется like this:


string msg = string.Empty;
string basedir = @"C:\Temp";
string xml = Path.Combine(basedir, "XML_FILE.xml");
string xsd = Path.Combine(basedir, "MAIN.xsd");

if (XmlUtils.ValidateAgainstXSD(xml, xsd, ref msg))
{
// do some work
}
else
{
Console.WriteLine(msg);
}

Console.ReadLine();


Любая помощь очень ценится - Спасибо!


ОБНОВЛЕНИЕ 2016-12-05:


Я написал свой собственный XmlUrlResolver, чтобы увидеть, что происходит за кулисами:


internal class XUrlResolver : XmlUrlResolver
{
public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)
{
return base.GetEntity(absoluteUri, role, ofObjectToReturn);
}

public override Uri ResolveUri(Uri baseUri, string relativeUri)
{
return base.ResolveUri(baseUri, relativeUri);
}
}


И я просто пытаюсь сделать:


XmlSchemaSet xset = new XmlSchemaSet();
xset.XmlResolver = new XUrlResolver();
xset.Add("", xsdFilePath);
xset.Compile();

Что происходит сейчас (в строке xset.Add):


    XmlUrlResolver.ResolveUri(null,"C:\\Temp\\MAIN.XSD"){file:///C:/Temp/MAIN.xsd}
    XmlUrlResolver.ResolveUri(null,"C:\\Temp\\MAIN.XSD"){file:///C:/Temp/MAIN.xsd}
    XmlUrlResolver.GetEntity({file:///C:/Temp/MAIN.xsd}) → Filestream to MAIN.xsd
    XmlUrlResolver.ResolveUri({file:///C:/Temp/MAIN.xsd},"TYPES.XSD"){file:///C:/Temp/TYPES.xsd}
    XmlUrlResolver.GetEntity({file:///C:/Temp/TYPES.xsd}) → Filestream to TYPES.xsd

Выглядит хорошо для меня (кроме первых двух вызовов равны!?!) - путь к TYPES.XSD разрешен так, как должен.


Тем не менее, xset.Compile() выбрасывает исключение: "Тип MY_AMOUNT не объявлен"


И я понятия не имею, почему:/

спросил(а) 2016-12-01T17:50:00+03:00 3 года, 10 месяцев назад
1
Решение
109

Я столкнулся с этой самой проблемой.

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

ответил(а) 2017-10-06T09:31:00+03:00 3 года назад
70

Сначала вам нужно сделать ваши файлы xsd действительными.


Types.xsd(добавлен корневой элемент схемы и пространство имен xs)


<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="MY_AMOUNT">
<xs:restriction base="xs:decimal">
<xs:maxInclusive value="999999999999.99"/>
<xs:minInclusive value="-999999999999.99"/>
<xs:totalDigits value="14"/>
<xs:fractionDigits value="2"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>

Main.xsd(удалены неверные ссылки).


<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:include schemaLocation="TYPES.xsd"/>
<xs:element name="ROOT">
<xs:complexType>
<xs:sequence>
<xs:element name="AMOUNT" type="MY_AMOUNT" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

После этого, учитывая, что оба файла xsd находятся в одном каталоге, ваши схемы будут скомпилированы.

ответил(а) 2016-12-05T13:59:00+03:00 3 года, 10 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема