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



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

872   13  

13 ответов:

библиотека времени выполнения Java поддерживает проверку. Последний раз, когда я проверял это был парсер Apache Xerces под обложками. Вы, вероятно, должны использовать javax.XML.утверждение.Валидатор.

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. Приведенный выше код проверяет дескриптор развертывания войны по URL http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd но вы можете так же легко проверить против локального файла.

вы не должны использовать DOMParser для проверьте документ (если ваша цель не заключается в создании объектной модели документа в любом случае). Это начнет создавать объекты DOM, поскольку он анализирует документ-расточительно, если вы не собираетесь их использовать.

вот как это сделать с помощью Xerces2. Учебник для этого, здесь (req. Регистрация).

оригинальная атрибуция: нагло скопирована из здесь:

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

Я нашел этот сайт, чтобы быть полезным, тоже.

http://www.ibm.com/developerworks/xml/library/x-javaxmlvalidapi.html

Это тот, который на самом деле работал для меня с минимумом суеты.

поскольку это популярный вопрос, я также хотел бы отметить, что java может проверять против "упомянутого" xsd, например, если .xml-файл сам определяет XSD, используя xsi:SchemaLocation или xsi:noNamespaceSchemaLocation (или xsi для определенных пространств имен), как указано здесь:

<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/document http://www.example.com/document.xsd">
  ...

" если вы создаете схему без указания 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 из сети, даже если url-адрес ссылки на xml-файлы, указав xsd вручную (см. некоторые другие ответы здесь) или используя "каталог XML" style resolver. Весна, видимо, тоже может перехватить запросы 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);

Смотрите также здесь для другого урока.

С помощью 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!
}

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

SAXCount -f -s -n my.xml

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

в debian squeeze он находится в пакете "libxerces-c-samples".

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

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

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

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

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

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

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

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

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

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

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

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

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-дневную пробную версию.

Comments

    Ничего не найдено.