Jaki jest najlepszy sposób walidacji pliku XML względem pliku XSD?

Generuję pliki xml, które muszą być zgodne z danym plikiem xsd. Jaki jest najlepszy sposób, aby zweryfikować ich zgodność?

Author: ScanQR, 2008-08-19

13 answers

Biblioteka Java runtime obsługuje walidację. Ostatnio sprawdzałem, czy to parser Apache Xerces pod okładkami. Powinieneś użyć javax.xml./ align = "left" / Walidator .

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) {}

Stała fabryczna schematu jest ciągiem http://www.w3.org/2001/XMLSchema, który definiuje XSD. Powyższy kod weryfikuje deskryptor wdrożenia wojny z adresem URL http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd, ale równie łatwo można go zweryfikować z lokalnym plikiem.

Nie powinieneś używać Domparsera do walidacji dokumentu (chyba że twój cel jest stworzenie modelu obiektowego dokumentu). Spowoduje to rozpoczęcie tworzenia obiektów DOM podczas przetwarzania dokumentu - marnotrawstwo, jeśli nie zamierzasz ich używać.

 341
Author: McDowell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-14 22:29:27

Oto Jak to zrobić używając Xerces2 . Tutorial do tego, tutaj (req. Rejestracja).

Original attribution: here :

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
Author: SCdF,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-13 18:16:51

Budujemy nasz projekt za pomocą ant, więc możemy użyć zadania schemavalidate, aby sprawdzić nasze pliki konfiguracyjne:

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

Teraz niegrzeczne pliki konfiguracyjne zawiodą naszą kompilację!

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

 20
Author: chickeninabiscuit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-14 08:01:05

Ponieważ jest to popularne pytanie, zwrócę uwagę, że java może również sprawdzać poprawność w stosunku do "referowanych" xsd, na przykład jeśli .plik XML sam określa XSD w nagłówku, używając xsi:schemaLocation lub xsi:noNamespaceSchemaLocation (lub xsi dla poszczególnych przestrzeni nazw) ex :

<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="http://www.example.com/document.xsd">
  ...
W przeciwieństwie do XSD, XSD może być używany do tworzenia map 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">
  ...

Inne odpowiedzi również działają tutaj, ponieważ .pliki xsd "mapują" do przestrzeni nazw zadeklarowanych wpliku xml, ponieważ deklarują one Przestrzeń nazw, i jeśli pasuje do przestrzeni nazw w .plik xml, jesteś dobry. Ale czasami wygodnie jest mieć niestandardowy resolver ...

From the javadocs: "jeśli tworzysz schemat bez podania adresu URL, pliku lub źródła, język Java tworzy taki, który wygląda w sprawdzanym dokumencie, aby znaleźć schemat, którego powinien używać. Na przykład: "

SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
Schema schema = factory.newSchema();

I to działa dla wielu przestrzeni nazw, itp. Problem z tym podejściem polega na tym, że xmlsns:xsi jest prawdopodobnie lokalizacji sieciowej, więc domyślnie wychodzi i uderza w sieć przy każdej walidacji, nie zawsze optymalnej.

Oto przykład, który sprawdza plik XML w oparciu o dowolne referencje XSD (nawet jeśli musi je pobrać z sieci):

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

Możesz uniknąć wyciągania odwołanych XSD z sieci, nawet jeśli pliki xml odwołują się do adresów url, podając xsd ręcznie (zobacz inne odpowiedzi tutaj) lub używając "XML catalog" style resolver. Wiosna najwyraźniej również może przechwycić żądania URL do serwowania plików lokalnych do walidacji. Możesz też ustawić swój własny poprzez setResourceResolver , ex:

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

Zobacz również tutaj aby uzyskać kolejny tutorial.

Domyślnym ustawieniem jest parsowanie DOM, możesz zrobić coś podobnego z parserem SAX, który również waliduje saxReader.setEntityResolver(your_resolver_here);

 16
Author: rogerdpack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-10 16:56:20

Używając Javy 7 możesz postępować zgodnie z dokumentacją zawartą w opisie pakietu .

// 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!
}
 6
Author: Paulo Fidalgo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-21 08:51:51

Jeśli masz maszynę z Linuksem, możesz użyć darmowego narzędzia wiersza poleceń SAXCount. Uznałem to za bardzo przydatne.

SAXCount -f -s -n my.xml

Sprawdza zgodność z dtd i xsd. 5s dla pliku 50MB.

W Debianie squeeze znajduje się w pakiecie "libxerces-c-samples".

Definicja dtd i xsd musi być w xml! Nie można konfigurować ich osobno.

 3
Author: juwens,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-22 17:01:25

Jeszcze jedna odpowiedź: ponieważ powiedziałeś, że musisz zweryfikować pliki, które generujesz (pisząc), możesz chcieć zweryfikować zawartość podczas pisania, zamiast najpierw pisać, a następnie czytać ponownie w celu walidacji. Prawdopodobnie możesz to zrobić z JDK API do walidacji Xml, jeśli używasz Writera opartego na SAX: jeśli tak, po prostu połącz się w walidatorze wywołując ' Validator.validate (source, result)', gdzie źródło pochodzi od Twojego pisarza, a wynik jest tam, gdzie wyjście musi iść.

Alternatywnie, jeśli użyj Stax do pisania treści (lub biblioteki, która używa lub może używać stax), Woodstox może również bezpośrednio wspierać walidację podczas korzystania z XMLStreamWriter. Oto wpis na blogu pokazujący, jak to się robi:

 3
Author: StaxMan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-10 09:57:05

Jeśli programowo generujesz pliki XML, możesz zajrzeć do biblioteki XMLBeans . Używając narzędzia wiersza poleceń, XMLBeans automatycznie wygeneruje i spakuje zestaw obiektów Java opartych na XSD. Następnie można użyć tych obiektów do zbudowania dokumentu XML na podstawie tego schematu.

Posiada wbudowaną obsługę walidacji schematu i może konwertować Obiekty Java na dokument XML i odwrotnie.

Castor i JAXB to inne Java biblioteki, które służą do podobnego celu jak XMLBeans.

 2
Author: Todd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-28 18:06:02

Z JAXB możesz użyć poniższego kodu:

    @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
    }
}
 2
Author: razvanone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-27 15:40:01

Używając Woodstox skonfiguruj parser StAX tak, aby sprawdzał poprawność twojego schematu i analizował XML.

Jeśli wyjątki są przechwytywane, XML nie jest poprawny, w przeciwnym razie jest poprawny:

// 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();
}

Uwaga: Jeśli chcesz zweryfikować wiele plików, spróbuj ponownie użyć XMLInputFactory i XMLValidationSchema, aby zmaksymalizować wydajność.

 1
Author: Loris Securo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-21 13:18:27

Szukasz narzędzia czy biblioteki?

Jeśli chodzi o biblioteki, de facto standardem jest Xerces2, który ma zarówno C++, jak i Java.

Ostrzegam jednak, że jest to rozwiązanie o dużej wadze. Ale z drugiej strony, Walidacja XML z plikami XSD jest dość dużym problemem wagi.

Jeśli chodzi o narzędzie do tego za Ciebie, XMLFox wydaje się być przyzwoitym rozwiązaniem freeware, ale nie używając go osobiście nie mogę powiedzieć za jasne.

 0
Author: Adam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-19 05:11:15

Sprawdzanie poprawności na schematach online

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

Validate against local schemas

Walidacja XML Offline za pomocą Javy

 0
Author: jschnasse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-09 14:23:05

Musiałem zweryfikować XML z XSD tylko jeden raz, więc próbowałem XMLFox. Uznałem to za bardzo mylące i dziwne. Instrukcje pomocy nie pasowały do interfejsu.

Skończyło się na użyciu LiquidXML Studio 2008 (v6), który był znacznie łatwiejszy w użyciu i od razu znajomy (interfejs jest bardzo podobny do Visual Basic 2008 Express, którego często używam). Wada: możliwość walidacji nie jest w wersji darmowej, więc musiałem użyć 30-dniowej wersji próbnej.

 -3
Author: KnomDeGuerre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-01 17:35:54