Проверка XML-файла по нескольким определениям схемы

Я пытаюсь проверить XML-файл на ряд различных схем (извинения за надуманный пример):

  • а.xsd-схемы
  • б.xsd-схемы
  • Си.xsd-схемы

c.xsd, в частности, импортирует b.xsd и b.xsd импортирует a.xsd, используя:

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

Я пытаюсь сделать это через Xerces следующим образом:

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)));

но это не удается импортировать все три схемы правильно в результате не удается разрешить имя "blah" для компонента(n) "group".

Я проверил это успешно, используя Python, но имея реальные проблемы с Java 6.0 и Xerces 2.8.1. Может ли кто-нибудь предложить, что здесь не так, или более простой подход для проверки моих XML-документов?

6 ответов


Так что на случай, если кто - то еще столкнется с той же проблемой здесь, мне нужно было загрузить родительскую схему (и неявные дочерние схемы) из модульного теста - как ресурс-для проверки строки XML. Я использовал Xerces XMLSchemFactory для этого вместе с валидатором Java 6.

чтобы правильно загрузить дочернюю схему через include, мне пришлось написать пользовательский распознаватель ресурсов. Код можно найти здесь:

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

чтобы использовать распознаватель, укажите его на фабрике схем:

xmlSchemaFactory.setResourceResolver(new ResourceResolver());

и он будет использовать его для разрешения ваших ресурсов через путь к классам (в моем случае из src/main/resources). Любые комментарии приветствуются...


http://www.kdgregory.com/index.php?page=xml.parsing секция'несколько схем для одного документа'

мое решение, основанное на этом документе:

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"));

из документации 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);

схема в Xerces (a) очень, очень педантична, и (b) дает совершенно бесполезные сообщения об ошибках, когда ему не нравится то, что он находит. Это разочаровывающее сочетание.

материал схемы в python может быть намного более прощающим и позволял небольшим ошибкам в схеме пройти незарегистрированным.

теперь, если, как вы говорите, c.xsd включает b.xsd и b.xsd включает a.xsd, тогда нет необходимости загружать все три в фабрику схем. Это не только не нужно, это будет вероятно, запутать Xerces и привести к ошибкам, так что это может быть ваша проблема. Просто передайте c.xsd на завод, и пусть он разрешит b.xsd и a.сам xsd, что он должен делать относительно c.xsd.


Я закончил использовать это:

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 {
    }
}

Не забудьте изменить:

1) параметр "http://your_url_schema_location" для вас расположение xsd-файла.

2) строку " / главная/пользователь / myfile.XML-код" для того, кто указывает на ваш xml-файл.

мне не нужно было устанавливать переменную:-Djavax.xml.validation.SchemaFactory:http://www.w3.org/2001/XMLSchema=org.apache.xerces.jaxp.validation.XMLSchemaFactory


я столкнулся с той же проблемой и после анализа было найдено это решение. Это работает на меня.

Enum настройки разные 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;
    }
}

метод проверки:

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.");
}