Pregunta Validar un archivo XML contra múltiples definiciones de esquema


Estoy tratando de validar un archivo XML contra varios esquemas diferentes (disculpas por el ejemplo inventado):

  • a.xsd
  • b.xsd
  • c.xsd

c.xsd, en particular, las importaciones b.xsd y b.xsd importan a.xsd, usando:

<xs:include schemaLocation="b.xsd"/>

Estoy tratando de hacer esto a través de Xerces de la siguiente manera:

XMLSchemaFactory xmlSchemaFactory = new XMLSchemaFactory();
Schema schema = xmlSchemaFactory.newSchema(new StreamSource[] { new StreamSource(this.getClass().getResourceAsStream("a.xsd"), "a.xsd"),
                                                         new StreamSource(this.getClass().getResourceAsStream("b.xsd"), "b.xsd"),
                                                         new StreamSource(this.getClass().getResourceAsStream("c.xsd"), "c.xsd")});     
Validator validator = schema.newValidator();
validator.validate(new StreamSource(new StringReader(xmlContent)));

pero esto no está logrando importar los tres esquemas correctamente, lo que resulta en que no se puede resolver el nombre 'blah' en un componente (n) 'grupo'.

He validado esto con éxito usando Pitón, pero teniendo problemas reales con Java 6.0 y Xerces 2.8.1. ¿Alguien puede sugerir qué está pasando mal aquí, o un enfoque más fácil para validar mis documentos XML?


32
2017-07-07 21:09


origen


Respuestas:


Entonces, en caso de que alguien más se encuentre con el mismo problema aquí, necesité cargar un esquema primario (y esquemas secundarios implícitos) a partir de una prueba unitaria, como recurso, para validar una Cadena XML. Usé Xerces XMLSchemFactory para hacer esto junto con el validador de Java 6.

Para cargar el esquema del niño correctamente a través de una inclusión, tuve que escribir una resolución de recursos personalizada. El código se puede encontrar aquí:

https://code.google.com/p/xmlsanity/source/browse/src/com/arc90/xmlsanity/validation/ResourceResolver.java

Para usar el resolver, especifíquelo en la fábrica del esquema:

xmlSchemaFactory.setResourceResolver(new ResourceResolver());

y lo usará para resolver tus recursos a través del classpath (en mi caso desde src / main / resources). Cualquier comentario es bienvenido en esto ...


17
2017-07-09 19:03



http://www.kdgregory.com/index.php?page=xml.parsing  sección 'Múltiples esquemas para un solo documento'

Mi solución basada en ese documento: 

URL xsdUrlA = this.getClass().getResource("a.xsd");
URL xsdUrlB = this.getClass().getResource("b.xsd");
URL xsdUrlC = this.getClass().getResource("c.xsd");

SchemaFactory schemaFactory = schemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
//---
String W3C_XSD_TOP_ELEMENT =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
   + "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" elementFormDefault=\"qualified\">\n"
   + "<xs:include schemaLocation=\"" +xsdUrlA.getPath() +"\"/>\n"
   + "<xs:include schemaLocation=\"" +xsdUrlB.getPath() +"\"/>\n"
   + "<xs:include schemaLocation=\"" +xsdUrlC.getPath() +"\"/>\n"
   +"</xs:schema>";
Schema schema = schemaFactory.newSchema(new StreamSource(new StringReader(W3C_XSD_TOP_ELEMENT), "xsdTop"));

6
2017-09-20 11:35



De la documentación de xerces: http://xerces.apache.org/xerces2-j/faq-xs.html

import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

...

StreamSource[] schemaDocuments = /* created by your application */;
Source instanceDocument = /* created by your application */;

SchemaFactory sf = SchemaFactory.newInstance(
    "http://www.w3.org/XML/XMLSchema/v1.1");
Schema s = sf.newSchema(schemaDocuments);
Validator v = s.newValidator();
v.validate(instanceDocument);

3
2018-03-28 08:31



El material de esquema en Xerces es (a) muy, muy pedante, y (b) da mensajes de error completamente inútiles cuando no le gusta lo que encuentra. Es una combinación frustrante.

Las cosas del esquema en Python pueden ser mucho más indulgentes, y dejaron pasar pequeños errores en el esquema no reportados.

Ahora bien, si, como dices, c.xsd incluye b.xsd y b.xsd incluye a.xsd, entonces no hay necesidad de cargar los tres en la fábrica de esquemas. No solo es innecesario, probablemente confundirá a Xerces y generará errores, por lo que este puede ser su problema. Simplemente pase c.xsd a la fábrica y deje que resuelva b.xsd y a.xsd, lo que debería hacer en relación con c.xsd.


2
2017-07-07 21:27



Terminé usando esto:

import org.apache.xerces.parsers.SAXParser;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
import java.io.IOException;
 .
 .
 .
 try {
        SAXParser parser = new SAXParser();
        parser.setFeature("http://xml.org/sax/features/validation", true);
        parser.setFeature("http://apache.org/xml/features/validation/schema", true);
        parser.setFeature("http://apache.org/xml/features/validation/schema-full-checking", true);
        parser.setProperty("http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation", "http://your_url_schema_location");

        Validator handler = new Validator();
        parser.setErrorHandler(handler);
        parser.parse("file:///" + "/home/user/myfile.xml");

 } catch (SAXException e) {
    e.printStackTrace();
 } catch (IOException ex) {
    e.printStackTrace();
 }


class Validator extends DefaultHandler {
    public boolean validationError = false;
    public SAXParseException saxParseException = null;

    public void error(SAXParseException exception)
            throws SAXException {
        validationError = true;
        saxParseException = exception;
    }

    public void fatalError(SAXParseException exception)
            throws SAXException {
        validationError = true;
        saxParseException = exception;
    }

    public void warning(SAXParseException exception)
            throws SAXException {
    }
}

Recuerde cambiar:

1) El parámetro "http: // your_url_schema_location" para su ubicación de archivo xsd.

2) La cadena "/home/user/myfile.xml" para el que apunta a su archivo xml.

No tuve que configurar la variable: -Djavax.xml.validation.SchemaFactory:http://www.w3.org/2001/XMLSchema=org.apache.xerces.jaxp.validation.XMLSchemaFactory 


1
2017-09-21 13:41



Enfrenté el mismo problema y después de investigar encontré esta solución. Esto funciona para mi.

Enum para configurar los diferentes XSDs:

public enum XsdFile {
    // @formatter:off
    A("a.xsd"),
    B("b.xsd"),
    C("c.xsd");
    // @formatter:on

    private final String value;

    private XsdFile(String value) {
        this.value = value;
    }

    public String getValue() {
        return this.value;
    }
}

Método para validar:

public static void validateXmlAgainstManyXsds() {
    final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

    String xmlFile;
    xmlFile = "example.xml";

    // Use of Enum class in order to get the different XSDs
    Source[] sources = new Source[XsdFile.class.getEnumConstants().length];
    for (XsdFile xsdFile : XsdFile.class.getEnumConstants()) {
        sources[xsdFile.ordinal()] = new StreamSource(xsdFile.getValue());
    }

    try {
        final Schema schema = schemaFactory.newSchema(sources);
        final Validator validator = schema.newValidator();
        System.out.println("Validating " + xmlFile + " against XSDs " + Arrays.toString(sources));
        validator.validate(new StreamSource(new File(xmlFile)));
    } catch (Exception exception) {
        System.out.println("ERROR: Unable to validate " + xmlFile + " against XSDs " + Arrays.toString(sources)
                + " - " + exception);
    }
    System.out.println("Validation process completed.");
}

0
2017-11-02 12:19