将XmlSchemaSet与XmlPreloadedResolver一起用于XDocument验证

时间:2016-09-13 12:44:41

标签: c# xml linq-to-xml

我正在尝试使用XDocument验证手动构建的XmlSchemaSet。 此外,我想使用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

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

1 个答案:

答案 0 :(得分:1)

显然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;
}