Подтвердить что ты не робот

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

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

  • a.xsd
  • b.xsd
  • c.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)));

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

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

4b9b3361

Ответ 1

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

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

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

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

xmlSchemaFactory.setResourceResolver(new ResourceResolver());

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

Ответ 2

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

Ответ 3

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

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

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

Ответ 4

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

Ответ 5

В итоге я использовал это:

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) Строка "/home/user/myfile.xml" для указателя на ваш XML файл.

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

Ответ 6

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

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