Я создаю некоторые файлы xml, которые должны соответствовать предоставленному мне файлу xsd. Как лучше всего проверить соответствие?
Как лучше всего проверить XML-файл на соответствие XSD-файлу?
Ответы (13)
Библиотека времени выполнения Java поддерживает проверку. В последний раз я проверял, что это парсер Apache Xerces. Вероятно, вам следует использовать javax.xml. валидация.Validator.
import javax.xml.XMLConstants;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.*;
import java.net.URL;
import org.xml.sax.SAXException;
//import java.io.File; // if you use File
import java.io.IOException;
...
URL schemaFile = new URL("http://host:port/filename.xsd");
// webapp example xsd:
// URL schemaFile = new URL("http://java.sun.com/xml/ns/j2ee/web-apphttp://www.w3.org/2001/XMLSchema
4.xsd");
// local file example:
// File schemaFile = new File("/location/to/localfile.xsd"); // etc.
Source xmlFile = new StreamSource(new File("web.xml"));
SchemaFactory schemaFactory = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
try {
Schema schema = schemaFactory.newSchema(schemaFile);
Validator validator = schema.newValidator();
validator.validate(xmlFile);
System.out.println(xmlFile.getSystemId() + " is valid");
} catch (SAXException e) {
System.out.println(xmlFile.getSystemId() + " is NOT valid reason:" + e);
} catch (IOException e) {}
Фабричная константа схемы - это строка http://www.w3.org/2001/XMLSchema
, которая определяет XSD. Приведенный выше код проверяет дескриптор развертывания WAR по URL-адресу http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd
, но вы также можете легко проверить его по локальному файлу.
Вы не должны использовать DOMParser для проверки документа (если ваша цель в любом случае не создать объектную модель документа). Это приведет к созданию объектов DOM по мере анализа документа - расточительно, если вы не собираетесь их использовать.
Вот как это сделать с помощью Xerces2. Руководство по этому вопросу, здесь (требуется регистрация) .
Оригинальная атрибуция: явно скопировано здесь:
import org.apache.xerces.parsers.DOMParser;
import java.io.File;
import org.w3c.dom.Document;
public class SchemaTest {
public static void main (String args[]) {
File docFile = new File("memory.xml");
try {
DOMParser parser = new DOMParser();
parser.setFeature("http://xml.org/sax/features/validation", true);
parser.setProperty(
"http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation",
"memory.xsd");
ErrorChecker errors = new ErrorChecker();
parser.setErrorHandler(errors);
parser.parse("memory.xml");
} catch (Exception e) {
System.out.print("Problem parsing the file.");
}
}
}
Мы собираем наш проект с помощью ant, поэтому мы можем использовать задачу schemavalidate для проверки наших файлов конфигурации:
<schemavalidate>
<fileset dir="${configdir}" includes="**/*.xml" />
</schemavalidate>
Теперь непослушные файлы конфигурации не помогут нашей сборке!
http://ant.apache.org/manual/Tasks/schemavalidate.html
Поскольку это популярный вопрос, я отмечу, что java также может проверять соответствие упомянутым xsd, например, если сам файл .xml указывает XSD в заголовке, используя xsi:schemaLocation
или xsi:noNamespaceSchemaLocation
(или xsi для определенных пространств имен) ex:
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.example.com/document.xsd">
...
или schemaLocation (всегда список пространств имен для сопоставлений xsd)
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.example.com/my_namespace http://www.example.com/document.xsd">
...
Другие ответы здесь также работают, потому что файлы .xsd сопоставляются с пространствами имен, объявленными в файле .xml, потому что они объявляют пространство имен, и если они совпадают с пространством имен в файле .xml, все в порядке. Но иногда бывает удобно иметь собственный преобразователь ...
Из документации javadocs: если вы создаете схему без указания URL-адреса, файла или источника, то язык Java создает схему, которая просматривает проверяемый документ, чтобы найти схему, которую он должен использовать. Например:
SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
Schema schema = factory.newSchema();
и это работает для нескольких пространств имен и т. д. Проблема с этим подходом заключается в том, что xmlsns:xsi
, вероятно, является сетевым местоположением, поэтому по умолчанию он будет выходить и попадать в сеть при каждой проверке, что не всегда оптимально.
Вот пример, который проверяет XML-файл на соответствие любым ссылкам XSD (даже если он должен вытащить их из сети):
public static void verifyValidatesInternalXsd(String filename) throws Exception {
InputStream xmlStream = new new FileInputStream(filename);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(true);
factory.setNamespaceAware(true);
factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage",
"http://www.w3.org/2001/XMLSchema");
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setErrorHandler(new RaiseOnErrorHandler());
builder.parse(new InputSource(xmlStream));
xmlStream.close();
}
public static class RaiseOnErrorHandler implements ErrorHandler {
public void warning(SAXParseException e) throws SAXException {
throw new RuntimeException(e);
}
public void error(SAXParseException e) throws SAXException {
throw new RuntimeException(e);
}
public void fatalError(SAXParseException e) throws SAXException {
throw new RuntimeException(e);
}
}
Вы можете избежать извлечения ссылочных XSD из сети, даже если xml-файлы ссылаются на URL-адреса, указав xsd вручную (см. Некоторые другие ответы здесь) или используя каталог XML преобразователь стилей. Spring, по-видимому, также может перехватывать URL-запросы для обслуживания локальных файлов для проверки. Или вы можете установить собственное через setResourceResolver, например:
Source xmlFile = new StreamSource(xmlFileLocation);
SchemaFactory schemaFactory = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema();
Validator validator = schema.newValidator();
validator.setResourceResolver(new LSResourceResolver() {
@Override
public LSInput resolveResource(String type, String namespaceURI,
String publicId, String systemId, String baseURI) {
InputSource is = new InputSource(
getClass().getResourceAsStream(
"some_local_file_in_the_jar.xsd"));
// or lookup by URI, etc...
return new Input(is); // for class Input see
// https://stackoverflow.com/a/2342859/32453
}
});
validator.validate(xmlFile);
См. Также здесь другое руководство.
Я считаю, что по умолчанию используется синтаксический анализ DOM, вы можете сделать что-то подобное с парсером SAX, который проверяет тоже saxReader.setEntityResolver(your_resolver_here);
setResourceResolver
, но кроме этого, возможно, откроете новый вопрос ...
- person rogerdpack; 25.07.2018
xsi:schemaLocation
вместо xsi:SchemaLocation
- дело имеет значение. См. w3.org/TR/xmlschema-1/#d0e3067.
- person Christian Schlichtherle; 09.09.2020
Используя Java 7, вы можете следовать документации, представленной в описание пакета.
// create a SchemaFactory capable of understanding WXS schemas SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); // load a WXS schema, represented by a Schema instance Source schemaFile = new StreamSource(new File("mySchema.xsd")); Schema schema = factory.newSchema(schemaFile); // create a Validator instance, which can be used to validate an instance document Validator validator = schema.newValidator(); // validate the DOM tree try { validator.validate(new StreamSource(new File("instance.xml")); } catch (SAXException e) { // instance document is invalid! }
parser.parse(new File("instance.xml"))
. validator
принимает Source
, поэтому вы можете: validator.validate(new StreamSource(new File("instance.xml")))
.
- person Alberto; 17.07.2014
ErrorHandler
, если вам нужно выполнить проверку.
- person Ludovic Kuty; 22.10.2017
Если у вас есть Linux-Machine, вы можете использовать бесплатный инструмент командной строки SAXCount. Я нашел это очень полезным.
SAXCount -f -s -n my.xml
Он проверяется на соответствие dtd и xsd. 5s для файла размером 50 МБ.
В debian squeeze он находится в пакете libxerces-c-samples.
Определение dtd и xsd должно быть в xml! Вы не можете настроить их отдельно.
xmllint --schema phone.xsd phone.xml
(из ответа 13ren)
- person rogerdpack; 19.12.2016
Еще один ответ: поскольку вы сказали, что вам нужно проверять файлы, которые вы генерируете (пишете), вы можете проверить контент во время записи, вместо того, чтобы сначала писать, а затем читать обратно для проверки. Вероятно, вы можете сделать это с помощью JDK API для проверки XML, если вы используете средство записи на основе SAX: если да, просто свяжите валидатор, вызвав 'Validator.validate (source, result)', где источник поступает от вашего писателя, а результат куда должен идти вывод.
В качестве альтернативы, если вы используете Stax для написания контента (или библиотеку, которая использует или может использовать stax), Woodstox может также напрямую поддерживают проверку при использовании XMLStreamWriter. Вот запись в блоге, показывающая, как это делается:
Если вы создаете файлы XML программно, вам может потребоваться библиотека XMLBeans. Используя инструмент командной строки, XMLBeans автоматически сгенерирует и упакует набор объектов Java на основе XSD. Затем вы можете использовать эти объекты для создания XML-документа на основе этой схемы.
Он имеет встроенную поддержку проверки схемы и может преобразовывать объекты Java в документ XML и наоборот.
Castor и JAXB - это другие библиотеки Java, которые служат той же цели, что и XMLBeans.
С JAXB вы можете использовать следующий код:
@Test
public void testCheckXmlIsValidAgainstSchema() {
logger.info("Validating an XML file against the latest schema...");
MyValidationEventCollector vec = new MyValidationEventCollector();
validateXmlAgainstSchema(vec, inputXmlFileName, inputXmlSchemaName, inputXmlRootClass);
assertThat(vec.getValidationErrors().isEmpty(), is(expectedValidationResult));
}
private void validateXmlAgainstSchema(final MyValidationEventCollector vec, final String xmlFileName, final String xsdSchemaName, final Class<?> rootClass) {
try (InputStream xmlFileIs = Thread.currentThread().getContextClassLoader().getResourceAsStream(xmlFileName);) {
final JAXBContext jContext = JAXBContext.newInstance(rootClass);
// Unmarshal the data from InputStream
final Unmarshaller unmarshaller = jContext.createUnmarshaller();
final SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
final InputStream schemaAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(xsdSchemaName);
unmarshaller.setSchema(sf.newSchema(new StreamSource(schemaAsStream)));
unmarshaller.setEventHandler(vec);
unmarshaller.unmarshal(new StreamSource(xmlFileIs), rootClass).getValue(); // The Document class is the root object in the XML file you want to validate
for (String validationError : vec.getValidationErrors()) {
logger.trace(validationError);
}
} catch (final Exception e) {
logger.error("The validation of the XML file " + xmlFileName + " failed: ", e);
}
}
class MyValidationEventCollector implements ValidationEventHandler {
private final List<String> validationErrors;
public MyValidationEventCollector() {
validationErrors = new ArrayList<>();
}
public List<String> getValidationErrors() {
return Collections.unmodifiableList(validationErrors);
}
@Override
public boolean handleEvent(final ValidationEvent event) {
String pattern = "line {0}, column {1}, error message {2}";
String errorMessage = MessageFormat.format(pattern, event.getLocator().getLineNumber(), event.getLocator().getColumnNumber(),
event.getMessage());
if (event.getSeverity() == ValidationEvent.FATAL_ERROR) {
validationErrors.add(errorMessage);
}
return true; // you collect the validation errors in a List and handle them later
}
}
Используя Woodstox, настройте синтаксический анализатор StAX для проверки соответствия вашей схеме и синтаксического анализа XML.
Если обнаружены исключения, XML недействителен, в противном случае он действителен:
// create the XSD schema from your schema file
XMLValidationSchemaFactory schemaFactory = XMLValidationSchemaFactory.newInstance(XMLValidationSchema.SCHEMA_ID_W3C_SCHEMA);
XMLValidationSchema validationSchema = schemaFactory.createSchema(schemaInputStream);
// create the XML reader for your XML file
WstxInputFactory inputFactory = new WstxInputFactory();
XMLStreamReader2 xmlReader = (XMLStreamReader2) inputFactory.createXMLStreamReader(xmlInputStream);
try {
// configure the reader to validate against the schema
xmlReader.validateAgainst(validationSchema);
// parse the XML
while (xmlReader.hasNext()) {
xmlReader.next();
}
// no exceptions, the XML is valid
} catch (XMLStreamException e) {
// exceptions, the XML is not valid
} finally {
xmlReader.close();
}
Примечание. Если вам нужно проверить несколько файлов, попробуйте повторно использовать свои XMLInputFactory
и XMLValidationSchema
, чтобы повысить производительность.
Вы ищете инструмент или библиотеку?
Что касается библиотек, то в значительной степени стандартом де-факто является Xerces2, в котором есть как C ++ и версии Java.
Однако будьте осторожны, это тяжелое решение. Но опять же, проверка XML по файлам XSD - довольно серьезная проблема.
Что касается инструмента, который сделает это за вас, XMLFox кажется достойным бесплатным решением, но не пользовался им лично, точно сказать не могу.
Проверять на соответствие онлайн-схемам
Source xmlFile = new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream("your.xml"));
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(Thread.currentThread().getContextClassLoader().getResource("your.xsd"));
Validator validator = schema.newValidator();
validator.validate(xmlFile);
Проверять по локальным схемам
Автономная проверка XML с помощью Java
Мне пришлось только один раз проверить XML на соответствие XSD, поэтому я попробовал XMLFox. Я нашел это очень запутанным и странным. Справочные инструкции не соответствовали интерфейсу.
В итоге я использовал LiquidXML Studio 2008 (v6), который был намного проще в использовании и более знакомым (пользовательский интерфейс очень похож на Visual Basic 2008 Express, который я часто использую). Недостаток: возможность проверки отсутствует в бесплатной версии, поэтому мне пришлось использовать 30-дневную пробную версию.