将 XmlSchemaSet 与 XmlPreloadedResolver 一起用于 XDocument 验证

Use of XmlSchemaSet with XmlPreloadedResolver for XDocument validation

我正在尝试使用 XmlSchemaSet 验证手动构建的 XDocument。 此外,我想利用 XmlPreloadedResolver 以便检索模式的本地副本并避免 Web 访问。

我添加了root schema的内容:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:enids="http://administracionelectronica.gob.es/ENI/XSD/v1.0/firma" 
xmlns:enidocmeta="http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/metadatos" 
xmlns:enifile="http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/contenido" 
xmlns:enidoc="http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e" 
targetNamespace="http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e" 
elementFormDefault="qualified" attributeFormDefault="unqualified">
    <xsd:annotation>
        <xsd:documentation xml:lang="es">XSD DOCUMENTO ENI (v1.0)</xsd:documentation>
    </xsd:annotation>
    <xsd:import namespace="http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/metadatos" schemaLocation="metadatosDocumentoEni.xsd"/>
    <xsd:import namespace="http://administracionelectronica.gob.es/ENI/XSD/v1.0/firma" schemaLocation="firmasEni.xsd"/>
    <xsd:import namespace="http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/contenido" schemaLocation="contenidoDocumentoEni.xsd"/>
    <xsd:element name="documento" type="enidoc:TipoDocumento">
        <xsd:annotation>
            <xsd:documentation xml:lang="es">El elemento "documento" podrá aparecer como elemento raíz de un documento XML objeto de intercambio o como elemento no raíz (elemento hijo).</xsd:documentation>
        </xsd:annotation>
    </xsd:element>
    <xsd:complexType name="TipoDocumento">
        <xsd:sequence>
            <xsd:element ref="enifile:contenido"/>
            <xsd:element ref="enidocmeta:metadatos"/>
            <xsd:element ref="enids:firmas" minOccurs="0" maxOccurs="1">
                <xsd:annotation>
                    <xsd:documentation xml:lang="es">La firma es obligatoria para el documento administrativo electrónico y para todo aquel documento electrónico susceptible de ser incorporado en un expediente electrónico.</xsd:documentation>
                </xsd:annotation>
            </xsd:element>
        </xsd:sequence>
        <xsd:attribute name="Id" type="xsd:ID" use="optional"/>
    </xsd:complexType>
</xsd:schema>

所以我为所有传递依赖构建了一个XmlPreloadedResolver,指向远程xsds的本地副本:

var resolver = new XmlPreloadedResolver();
resolver.add(
"http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/contenido", 
File.ReadAllBytes("local/path/to/contenidoDocumentoEni.xsd"));
...

然后我创建一个 SchemaSet 包括根模式:

var settings = new XmlReaderSettings {
                XmlResolver = resolver,
                DtdProcessing = DtdProcessing.Parse
            };

var schemaSet = new XmlSchemaSet();


using (var fs = new FileStream("./local/path/to/documentoEni.xsd", FileMode.Open))
using (var xr = XmlReader.Create(fs, settings))
{
    schemaSet.Add(_enidoc.NamespaceName, xr);
}
schemaSet.Compile();

我收到 XmlSchemaValidationException: the element http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/contenido:contenido is not declared.

该元素是在第一个依赖项中定义的,所以我想我没有正确创建 XmlPreloadedResolverXmlSchemaSet

我认为这些模式是正确的,因为它们被无数的应用程序使用。

显然 XmlSchemaSet 需要将所有本地引用的架构添加到集合中,或者 XmlPreloadedResolver 无法解析为提供的 URIs

我已经设法通过手动将模式添加到 XmlSchemaSet 来让它工作:

public static XmlSchemaSet SchemaSet() {

    XNamespace enidoc =
        "http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e";
    XNamespace enidocMeta =
        "http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/metadatos";
    XNamespace enids = "http://administracionelectronica.gob.es/ENI/XSD/v1.0/firma";
    XNamespace enifile =
        "http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/contenido";
    XNamespace ds = "http://www.w3.org/2000/09/xmldsig#";

    var namespaces =
        new Dictionary < XNamespace, string > { 
            { enidoc, "./Schemas/Eni/documentoEni.xsd"}, 
            { enidocMeta, "./Schemas/Eni/metadatosDocumentoEni.xsd"}, 
            { enids, "./Schemas/Eni/firmasEni.xsd"}, 
            { enifile, "./Schemas/Eni/contenidoDocumentoEni.xsd" }, 
            { ds, "./Schemas/Eni/xmldsig-core-schema.xsd" }
    };

    var schemaSet = new XmlSchemaSet();

    foreach(var ns in namespaces) {
        using(var fs = new FileStream(ns.Value, FileMode.Open))
        using(var xr = XmlReader.Create(fs)) {
            schemaSet.Add(ns.Key.NamespaceName, xr);
        }
    }

    schemaSet.Compile();
    return schemaSet;
}