使用包含的 xsd 文件编译模式
compile schemas with included xsd files
我有静态方法,我用它来根据 XSD 文件验证 XML 文件。这工作正常,直到有一个 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>
验证码:
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 文件始终位于同一目录中!
方法调用如下:
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})
--> 文件流到 MAIN.xsd
XmlUrlResolver.ResolveUri({file:///C:/Temp/MAIN.xsd},"TYPES.XSD")
--> {file:///C:/Temp/TYPES.xsd}
XmlUrlResolver.GetEntity({file:///C:/Temp/TYPES.xsd})
--> 文件流到 TYPES.xsd
我觉得不错(除了前 2 个调用是相等的!?!)- TYPES.XSD 的路径已按预期解析。
然而,xset.Compile()
抛出异常:"Type MY_AMOUNT is not declared"
我不知道为什么:/
首先,您需要使 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 文件都在同一目录中,您的模式将编译正常。
我 运行 遇到了同样的问题。
我并不是说这是 正确的 答案,但我通过将 Environment.CurrentDirectory
属性 设置为包含的 XSD 位于。然后就全部处理好了。
我有静态方法,我用它来根据 XSD 文件验证 XML 文件。这工作正常,直到有一个 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>
验证码:
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 文件始终位于同一目录中!
方法调用如下:
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})
--> 文件流到 MAIN.xsdXmlUrlResolver.ResolveUri({file:///C:/Temp/MAIN.xsd},"TYPES.XSD")
-->{file:///C:/Temp/TYPES.xsd}
XmlUrlResolver.GetEntity({file:///C:/Temp/TYPES.xsd})
--> 文件流到 TYPES.xsd
我觉得不错(除了前 2 个调用是相等的!?!)- TYPES.XSD 的路径已按预期解析。
然而,xset.Compile()
抛出异常:"Type MY_AMOUNT is not declared"
我不知道为什么:/
首先,您需要使 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 文件都在同一目录中,您的模式将编译正常。
我 运行 遇到了同样的问题。
我并不是说这是 正确的 答案,但我通过将 Environment.CurrentDirectory
属性 设置为包含的 XSD 位于。然后就全部处理好了。