簡體   English   中英

使用XSD模式驗證XML,該模式包含C#中的DTD聲明

[英]Validate an XML using XSD schema that contains DTD declarations in C#

我一直在嘗試使用XSD文件的層次結構來驗證XML文件,其中一些包含dtd文件。 我通過設置驗證標志ProcessInlineSchemaProcessSchemaLocation ,成功地基於通過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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM