[英]Validate an XML using XSD schema that contains DTD declarations in C#
我一直在嘗試使用XSD文件的層次結構來驗證XML文件,其中一些包含dtd文件。 我通過設置驗證標志ProcessInlineSchema
和ProcessSchemaLocation
,成功地基於通過XML文件中的schemaLocation引用的模式成功完成了此操作。
但是,對於我的情況,我需要將XSD文件與正在構建的應用程序一起交付,因此應該忽略schemaLocation(因為它會指向Web上的某個位置)。 XML文件是標准的。
我創建了一個簡單的示例來測試我的問題-我有以下文件:
main.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="ro:sopa:main" xmlns:main="ro:sopa:main" xmlns:inc="ro:sopa:inc" >
<xs:import namespace="ro:sopa:inc" schemaLocation="included.xsd"/>
<xs:element name="test" type="main:testType"/>
<xs:complexType name="testType">
<xs:sequence>
<xs:element name="test1" type="inc:testInc" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
included.xsd
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xs:schema [
<!ENTITY % inc.dtd SYSTEM "inc.dtd">
%inc.dtd;
]>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="ro:sopa:inc">
<xs:simpleType name="testInc">
<xs:restriction base="xs:string">
<xs:pattern value="&test;"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
dtd
<!ENTITY digit "[0-9]{1}">
<!ENTITY alnum "[A-Z]{1}">
<!ENTITY test "&alnum;-&digit;">
示例XML文件:
<main:test xsi:schemaLocation="ro:sopa:main D:\schemas\main.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:main="ro:sopa:main">
<test1>A-4</test1>
</main:test>
如果我直接針對XML文件中指向的架構進行驗證,則它可以正常工作:
List<string> report = new List<string>();
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.DtdProcessing = DtdProcessing.Parse;
settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
settings.ValidationEventHandler += new ValidationEventHandler(delegate(object snd, ValidationEventArgs e2)
{
report.Add(e2.Message);
});
XmlReader reader = XmlReader.Create(fileName, settings);
while (reader.Read());
reader.Close();
但是,如果我嘗試手動設置XmlSchemaSet,它將無法正常工作。
public static string schemaUrl = @"D:\schema\main.xsd";
public static string fileName = @"D:\somewhere\testProd1.xml";
public static void Main(string[] args)
{
List<string> report = new List<string>();
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.DtdProcessing = DtdProcessing.Parse;
settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
settings.Schemas = ProvideSchemaSet(report);
settings.ValidationEventHandler += new ValidationEventHandler(delegate(object snd, ValidationEventArgs e2)
{
report.Add(e2.Message);
});
XmlReader reader = XmlReader.Create(fileName, settings);
while (reader.Read()) ;
reader.Close();
}
public static XmlSchemaSet ProvideSchemaSet(List<string> schemaLoadErrors)
{
XmlSchemaSet schemas = new XmlSchemaSet();
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Parse;
XmlReader schemaReader = XmlReader.Create(schemaUrl, settings);
XmlSchema schema = XmlSchema.Read(schemaReader, delegate(object sender, ValidationEventArgs e)
{
schemaLoadErrors.Add(e.Message);
});
schemas.Add(schema);
schemaReader.Close();
schemas.Compile();
return schemas;
}
這將在schemas.Compile()上崩潰,表明對象test1不存在。 僅當我使用dtd時才會發生這種情況-如果我將DTD從模式中取出,則它可以正常工作。
我在互聯網上搜索的所有內容都是關於XSD驗證或有關DTD驗證的-但是我沒有找到任何解決方案。 有什么建議么?
注意:我必須使用的模式和DTD是標准化的,因此我無法以任何方式更改它們。
您可以重新加載XSD,處理DTD部分,然后將其刪除
XmlReaderSettings xrs = new XmlReaderSettings();
xrs.DtdProcessing = DtdProcessing.Parse;
xrs.IgnoreProcessingInstructions = false;
xrs.XmlResolver = new XmlUrlResolver();
XmlReader reader = XmlReader.Create(@"c:\temp\xsd\included.xsd", xrs);
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(reader);
Debug.WriteLine(xmldoc.OuterXml);
這將為您提供一個看起來像這樣的XML文檔
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xs:schema[
<!ENTITY % inc.dtd SYSTEM "inc.dtd">%inc.dtd;
]>
<!-- Created with Liquid Studio 2018 BETA - Developer Bundle (Educational) 16.0.0.7863 (https://www.liquid-technologies.com) -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="ro:sopa:inc">
<xs:simpleType name="testInc">
<xs:restriction base="xs:string">
<xs:pattern value="[A-Z]{1}-[0-9]{1}" />
</xs:restriction>
</xs:simpleType>
</xs:schema>
然后,您可以刪除DocType(這可能會使XSD編譯混亂)
foreach (var xmlDocType in xmldoc.ChildNodes.OfType<XmlDocumentType>().ToArray())
xmldoc.RemoveChild(xmlDocType);
Debug.WriteLine(xmldoc.OuterXml);
離開這個
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Liquid Studio 2018 BETA - Developer Bundle (Educational) 16.0.0.7863 (https://www.liquid-technologies.com) -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="ro:sopa:inc">
<xs:simpleType name="testInc">
<xs:restriction base="xs:string">
<xs:pattern value="[A-Z]{1}-[0-9]{1}" />
</xs:restriction>
</xs:simpleType>
</xs:schema>
盡管將DTD嵌入XSD是合法的,但我認為這是個壞主意,但它確實引發了許多驗證器和工具。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.