Проверка 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, мне пришлось написать пользовательский распознаватель ресурсов. Код можно найти здесь:
чтобы использовать распознаватель, укажите его на фабрике схем:
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.");
}