【问题标题】:Validate an XML using XSD schema that contains DTD declarations in C#使用包含 C# 中的 DTD 声明的 XSD 架构验证 XML
【发布时间】:2017-11-20 17:28:41
【问题描述】:

我一直在尝试使用 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>

包含的.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>

inc.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 是标准化的,因此我无法以任何方式更改它们。

【问题讨论】:

    标签: c# validation xsd schema dtd


    【解决方案1】:

    您可以重新加载 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>
    

    虽然在 XSD 中嵌入 DTD 是合​​法的,但我认为这是个坏主意,但它确实会抛出很多验证器和工具。

    【讨论】:

      猜你喜欢
      • 2011-06-12
      • 2014-09-28
      • 1970-01-01
      • 2021-03-04
      • 2012-09-16
      • 1970-01-01
      • 1970-01-01
      • 2011-06-18
      • 2022-01-10
      相关资源
      最近更新 更多