Каков наилучший способ проверки XML-файла по сравнению с XSD-файлом?

Я генерирую некоторые xml-файлы, которые должны соответствовать xsd-файлу, который мне дали. Какой лучший способ проверить их соответствие?

19.08.2008 04:59:04
13 ОТВЕТОВ
РЕШЕНИЕ

Библиотека времени выполнения Java поддерживает проверку. В прошлый раз, когда я проверял, это был парсер Apache Xerces под одеялом. Вы, вероятно, должны использовать javax.xml.validation.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-app_2_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 при анализе документа - расточительно, если вы не собираетесь их использовать.

335
14.06.2017 22:29:27
Используете ли вы DOM или SAX парсер в этом примере? Как я могу сказать, какой парсер вы используете, так как я не вижу ссылки ни на один из них.
ziggy 21.07.2012 12:15:02
@ziggy - это деталь реализации JAXP . JDK 6 от Sun использует SAX-парсер с StreamSource . В этом случае реализация JAXP может легально использовать синтаксический анализатор DOM, но для этого нет причин. Если вы используете для проверки явным образом DOM-анализатор , вы обязательно создадите экземпляр дерева DOM.
McDowell 21.07.2012 14:56:25
Как я могу использовать ErrorHandler с вышеуказанным? Это случай просто создания ErrorHandler и связывания его с валидатором? то есть validator.SetErrorHandler (), как в примере в этом вопросе SO stackoverflow.com/questions/4864681/… ?
ziggy 22.07.2012 18:14:06
Разве исключения не должны использоваться только для исключительных ситуаций, а не для потока управления?
mike 19.07.2013 14:48:18
Разве этот код не ловит только фатальные ошибки? Если вы хотите быть в состоянии поймать нефатальных (например, неструктурных), я думаю, вам нужно будет использовать ErrorHandler.
matt forsythe 30.05.2014 21:13:05

Вот как это сделать с помощью 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.");
     }
  }
}
25
13.04.2017 18:16:51
Парсер SAX был бы более эффективным - парсер DOM создает объекты DOM; расточительные операции в этом случае.
McDowell 17.09.2008 21:02:06
Вопрос заключается в проверке XML на соответствие XSD. В этом ответе вы идете дальше и получаете объект Parser, который не нужен, верно?
Weslor 29.10.2015 13:43:50
Msgstr "ErrorChecker не может быть преобразован в тип" .. отсутствует импорт?
Alex 11.03.2016 11:33:04

Вы ищете инструмент или библиотеку?

Что касается библиотек, то фактически стандартом де-факто является Xerces2, который имеет версии C ++ и Java .

Будьте предупреждены, хотя, это решение тяжелого веса. Но опять же, проверка XML по файлам XSD является довольно сложной проблемой.

Что касается инструмента, который сделает это за вас, то XMLFox кажется неплохим бесплатным решением, но я не могу сказать наверняка, что не использовал его лично.

0
19.08.2008 05:11:15

Мне пришлось проверять XML на XSD всего один раз, поэтому я попробовал XMLFox. Я нашел это очень запутанным и странным. Инструкции справки не соответствуют интерфейсу.

В итоге я использовал LiquidXML Studio 2008 (v6), который был намного проще в использовании и более знакомым (пользовательский интерфейс очень похож на Visual Basic 2008 Express, который я часто использую). Недостаток: возможность проверки отсутствует в бесплатной версии, поэтому мне пришлось использовать 30-дневную пробную версию.

-3
1.10.2008 17:35:54
Вопрос в Java, но это не так. :-(
james.garriss 7.10.2015 16:45:13
Чтобы быть справедливым, слово "java" никогда не появляется в вопросе, только теги. Я бы ответил на этот вопрос, а не на ответ.
Mark Storer 7.12.2018 22:38:21
Спасибо Джеймс и Марк, помогите мне обострить!
Knom 10.12.2018 14:26:11

Если вы генерируете XML-файлы программно, вы можете обратиться к библиотеке XMLBeans . Используя инструмент командной строки, XMLBeans автоматически генерирует и упаковывает набор объектов Java на основе XSD. Затем вы можете использовать эти объекты для создания XML-документа на основе этой схемы.

Он имеет встроенную поддержку проверки схемы и может преобразовывать объекты Java в документ XML и наоборот.

Castor и JAXB - это другие библиотеки Java, которые служат аналогичным целям XMLBeans.

2
28.01.2009 18:06:02

Еще один ответ: так как вы сказали, что вам нужно проверять файлы, которые вы генерируете (записываете), вы можете проверить контент во время записи, вместо того, чтобы сначала писать, а затем читать обратно для проверки. Вероятно, вы можете сделать это с помощью JDK API для проверки Xml, если вы используете средство записи на основе SAX: если это так, просто создайте ссылку в валидаторе, вызвав Validator.validate (source, result), где источник исходит от вашего средства записи, а результат где выход должен идти.

В качестве альтернативы, если вы используете Stax для написания контента (или библиотеку, которая использует или может использовать stax), Woodstox также может напрямую поддерживать проверку при использовании XMLStreamWriter. Вот запись в блоге, показывающая, как это делается:

3
10.01.2018 09:57:05
Привет, StaxMan, есть ли какие-нибудь XMLStreamWriters, которые делают отступы при красивой печати? Я был удивлен, что это не в стандартной реализации. Кроме того, это получает много пользы? Я думаю, что это правильный путь, но, похоже, это мало интересует.
13ren 28.03.2009 08:31:29
только что нашел ваш пост здесь о StaxMate (но это не XMLStreamWriter): stackoverflow.com/questions/290326/stax-xml-formatting-in-java/…
13ren 28.03.2009 08:47:41
Да, StaxMate может сделать это. Он использует XMLStreamWriter для записи содержимого, поэтому вы также можете подключить валидатор.
StaxMan 1.04.2010 05:56:57

Мы строим наш проект с помощью ant, поэтому мы можем использовать задачу schemavalidate для проверки наших файлов конфигурации:

<schemavalidate> 
    <fileset dir="${configdir}" includes="**/*.xml" />
</schemavalidate>

Теперь непослушные конфигурационные файлы не получатся в нашей сборке

http://ant.apache.org/manual/Tasks/schemavalidate.html

20
14.07.2011 08:01:05

Если у вас есть Linux-машина, вы можете использовать бесплатный инструмент командной строки SAXCount. Я нашел это очень полезным.

SAXCount -f -s -n my.xml

Это проверяет против dtd и xsd. 5 с для файла 50 МБ.

В Debian Squeeze он находится в пакете "libxerces-c-samples".

Определение dtd и xsd должно быть в xml! Вы не можете настроить их отдельно.

3
22.03.2012 17:01:25
Это позволяет выполнять простую проверку XML из vim (:! SAXCount -f -n -s%)
Shane 18.07.2012 04:05:06
или используйте почтенный xmllint xmllint --schema phone.xsd phone.xml(из ответа 13ren)
rogerdpack 19.12.2016 15:42:21

Используя Java 7, вы можете следовать документации, представленной в описании пакета .

// parse an XML document into a DOM tree
DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document document = parser.parse(new File("instance.xml"));

// 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 DOMSource(document));
} catch (SAXException e) {
    // instance document is invalid!
}
5
13.05.2013 09:40:38
«Использование Java 7 ..» Это было на самом деле включено в Java 5 .
Andrew Thompson 20.08.2013 21:05:10
Это в основном так же, как принятый ответ . Это решение мне кажется немного неэффективным , хотя, как это излишне строит DOM для XML для синтаксического анализа: parser.parse(new File("instance.xml")). validatorПринимает Source, так что вы можете: validator.validate(new StreamSource(new File("instance.xml"))).
Alberto 17.07.2014 04:55:11
Работая таким образом, SAXException генерируется при первой ошибке в xml-файле и останавливает проверку. Но я хочу знать все (!) Ошибки. Если вместо этого я использую ErrorHandler (собственный класс, который реализует ErrorHandler), он распознает все ошибки, но блок try-catch для validator.validate не выдает никаких исключений. Как распознать ошибку в классе, который вызывает валидацию метод моего валидатора? Спасибо за вашу помощь!
mrbela 13.01.2015 10:44:39
Существуют «ошибки» (например, ошибки валидации) и «фатальные ошибки» (ошибки корректности). Одна фатальная ошибка обычно останавливает синтаксический анализ. Но ошибка проверки не останавливает ее: вы должны явно выбросить исключение. Таким образом, необходимо предоставить, ErrorHandlerесли вам нужно сделать проверку.
Ludovic Kuty 22.10.2017 06:04:42
Должен признать, что код выглядит чище и легче читать, чем принятый ответ.
Clockwork 17.01.2019 16:22:29

Так как это популярный вопрос, я укажу, что 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);

13
6.02.2019 18:19:15
У меня не работает, метод resolResource () не вызывается, если он не установлен на schemaFactory, есть идеи?
tomasb 25.07.2018 14:21:30
Незнайка, у меня работает. Удостоверьтесь, что вы устанавливаете это через, setResourceResolverно кроме этого, возможно, откройте новый вопрос ...
rogerdpack 25.07.2018 15:55:26

С 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
    }
}
1
27.11.2017 15:40:01

Проверка по сетевым схемам

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

0
9.10.2018 14:23:05

Используя 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увеличить производительность.

0
21.09.2019 13:18:27