Jaki jest najlepszy sposób sprawdzenia poprawności pliku XML względem pliku XSD?


Tworzę pliki xml, które muszą pasować do otrzymanego pliku xsd. Jaki jest najlepszy sposób sprawdzenia ich zgodności?
Zaproszony:
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Biblioteka środowiska wykonawczego Java obsługuje sprawdzanie poprawności. Ostatnim razem, gdy sprawdzałem, był to parser Apache Xerces pod okładką. Powinieneś prawdopodobnie użyć

javax.xml.validation.Validator
http://java.sun.com/j2se/1.5.0 ... .html
.
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("[url=http://host:port/filename.xsd"]http://host:port/filename.xsd"[/url];);
// webapp example xsd:
// URL schemaFile = new URL("[url=http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"]http://java.sun.com/xml/ns/j2e ... 6quot[/url];);
// 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 to
[url=http://www.w3.org/2001/XMLSchema]http://www.w3.org/2001/XMLSchema[/url]
, która definiuje pliki XSD. Powyższy kod porównuje deskryptor wdrażania WAR z adresem URL
[url=http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd]http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd[/url]
, ale równie łatwo można to porównać z plik lokalny.
Nie powinieneś używać DOMParser do walidacji dokumentu (chyba że Twoim celem jest i tak utworzenie modelu obiektowego dokumentu). Spowoduje to utworzenie obiektów DOM podczas przetwarzania dokumentu - marnotrawstwo, jeśli nie zamierzasz ich używać.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Oto jak to zrobić

Xerces2
http://xerces.apache.org/xerces2-j/... Poradnik do tego

tutaj
http://www.ibm.com/developerwo ... .html
(req. signup).
Oryginalne źródło: bezczelnie skopiowane stąd:
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("[url=http://xml.org/sax/features/validation"]http://xml.org/sax/features/validation"[/url], true);
parser.setProperty( "[url=http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation"]http://apache.org/xml/properti ... ot%3B[/url],
"memory.xsd");
ErrorChecker errors = new ErrorChecker();
parser.setErrorHandler(errors);
parser.parse("memory.xml");
} catch (Exception e) {
System.out.print("Problem parsing the file.");
}
}
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Budujemy nasz projekt przy użyciu ant, więc możemy użyć zadania schemavalidate do sprawdzenia poprawności naszych plików konfiguracyjnych:
<schemavalidate> 
<fileset dir="${configdir}" includes="**/*.xml"/>
</schemavalidate>

Teraz niegrzeczne pliki konfiguracyjne nie będą w stanie ukończyć naszej kompilacji!
http://ant.apache.org/manual/T ... .html
http://ant.apache.org/manual/T ... .html
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Ponieważ jest to popularne pytanie, zauważam, że java może również sprawdzić w odniesieniu do xsd, na przykład, jeśli sam plik .xml określa XSD w nagłówku za pomocą
xsi: SchemaLocation
lub
xsi: noNamespaceSchemaLocation
(lub xsi dla określonych przestrzeni nazw)

.
http://www.ibm.com/developerwo ... .html
:
<document xmlns:xsi="[url=http://www.w3.org/2001/XMLSchema-instance"]http://www.w3.org/2001/XMLSchema-instance"[/url]
xsi:noNamespaceSchemaLocation="[url=http://www.example.com/document.xsd">]http://www.example.com/document.xsd">[/url]
...

lub SchemaLocation (zawsze lista mapowań przestrzeni nazw w xsd)
<document xmlns:xsi="[url=http://www.w3.org/2001/XMLSchema-instance"]http://www.w3.org/2001/XMLSchema-instance"[/url]
xsi:SchemaLocation="[url=http://www.example.com/my_namespace]http://www.example.com/my_namespace[/url] [url=http://www.example.com/document.xsd">]http://www.example.com/document.xsd">[/url]
...

Inne odpowiedzi również działają tutaj, ponieważ pliki .xsd „odwzorowują” przestrzenie nazw zadeklarowane w pliku .xml, ponieważ deklarują przestrzeń nazw, a jeśli pasuje ona do przestrzeni nazw w pliku .xml, to dobrze. Ale czasami wygodnie jest mieć własny

solver
https://stackoverflow.com/a/2342859/32453
...
Z javadocs: „jeśli utworzysz schemat bez określania adresu URL, pliku lub źródła, język Java utworzy ten, który przeszukuje sprawdzany dokument w celu znalezienia schematu, którego powinien użyć. Na przykład:”
SchemaFactory factory = SchemaFactory.newInstance("[url=http://www.w3.org/2001/XMLSchema"]http://www.w3.org/2001/XMLSchema"[/url];);
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 lokalizacją sieciową, więc domyślnie wychodzi i przechodzi do trybu online przy każdym sprawdzeniu, nie zawsze jest to optymalne.
Oto przykład, który sprawdza plik XML pod kątem jakichkolwiek odniesień do XSD (nawet jeśli musi wyciągnąć je 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("[url=http://java.sun.com/xml/jaxp/properties/schemaLanguage"]http://java.sun.com/xml/jaxp/p ... ot%3B[/url],
"[url=http://www.w3.org/2001/XMLSchema"]http://www.w3.org/2001/XMLSchema"[/url];);
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ąć pobierania plików XSD, do których istnieją odwołania, z sieci WWW, nawet jeśli do plików xml znajdują się odwołania do adresów URL, określając xsd ręcznie (zobacz inne odpowiedzi tutaj) lub używając

rozpoznawanie stylu
https://coderoad.ru/25698764/
„Katalog XML”. Podobno wiosna też

może przechwycić
https://stackoverflow.com/a/10768972/32453
prośby o url dotyczące serwowania plików lokalnych do sprawdzenia. Lub możesz zainstalować własne za pośrednictwem

setResourceResolver
https://docs.oracle.com/javase ... olver(org.w3c.dom.ls.LSResourceResolver)
, 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
// [url=https://stackoverflow.com/a/2342859/32453]https://stackoverflow.com/a/2342859/32453[/url]
}
});
validator.validate(xmlFile);

Zobacz też

tutaj
https://docs.oracle.com/javase ... .html
kolejny samouczek.
Uważam, że domyślnym jest parsowanie DOM, możesz zrobić coś takiego z parserem SAX, który

również
https://blog.frankel.ch/use-lo ... -xml/
sprawdza
saxReader.setEntityResolver (your_resolver_here);
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Używając Java 7 możesz postępować zgodnie z dokumentacją podaną w

opis pakietu
http://docs.oracle.com/javase/ ... .html
.

// 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!
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Inna odpowiedź: skoro powiedziałeś, że musisz sprawdzić pliki

Stwórz

(napisz), możesz sprawdzić zawartość podczas pisania, zamiast najpierw pisać, a potem czytać, aby sprawdzić. Prawdopodobnie możesz to zrobić za pomocą JDK API, aby zweryfikować XML, jeśli używasz programu zapisującego opartego na SAX: jeśli tak, po prostu połącz walidator z wywołaniem `` Validator.validate (źródło, wynik) '', gdzie źródło pochodzi z twojego writer., a wynik jest tam, gdzie dane wyjściowe powinny być.
Ponadto, jeśli używasz Stax do pisania treści (lub biblioteki, która używa lub może używać stax), Woodstox

również
https://github.com/FasterXML/woodstox
może bezpośrednio obsługiwać walidację podczas korzystania z XMLStreamWriter. Tutaj

post na blogu
http://www.cowtowncoder.com/bl ... .html
pokazując, jak to się robi:
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Jeśli masz komputer z systemem Linux, możesz skorzystać z bezpłatnego narzędzia wiersza poleceń SAXCount. Uznałem to za bardzo pomocne.
SAXCount -f -s -n my.xml

Sprawdza przed dtd i xsd.
5s dla pliku o wielkości 50 MB.
W debian squeeze znajduje się w pakiecie „libxerces-c-samples”.
Definicja dtd i xsd musi być w formacie xml! Nie można ich dostosowywać oddzielnie.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Jeśli tworzysz pliki XML programowo, możesz zajrzeć do biblioteki

XMLBeans
http://xmlbeans.apache.org/... Korzystając z narzędzia wiersza poleceń, XMLBeans automatycznie utworzy i zapakuje zestaw obiektów Java opartych na XSD. Obiekty te można następnie wykorzystać do zbudowania dokumentu XML na podstawie tego schematu.
Posiada wbudowaną obsługę walidacji schematów i może konwertować obiekty Java na dokument XML i odwrotnie.
Castor
http://www.castor.org/
i

JAXB
http://java.sun.com/developer/ ... jaxb/
to inne biblioteki Java, które służą temu samemu celowi co XMLBeans.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Z JAXB możesz użyć następującego 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
}
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Szukasz narzędzia lub biblioteki?
Jeśli chodzi o biblioteki, Xerces2 jest de facto standardem.

,
http://xerces.apache.org
który ma obie wersje

C++
http://xerces.apache.org/xerces-c/
i

Java
http://xerces.apache.org/xerces2-j/
.
Pamiętaj jednak, że jest to kłopotliwa decyzja. Ale znowu, walidacja XML względem plików XSD jest dość trudnym problemem.
Jeśli chodzi o narzędzie, które zrobi to za Ciebie,

XMLFox
http://www.xmlfox.com/xml_editor.htm
wydaje się przyzwoitym darmowym rozwiązaniem, ale bez korzystania z niego osobiście nie mogę powiedzieć na pewno.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:


Sprawdzanie według schematów sieciowych

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


Sprawdzenie schematu lokalnego

Walidacja XML w trybie offline za pomocą Java Baeldung
https://stackoverflow.com/a/48447453/1485527
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Za pomocą

Woodstox
https://github.com/FasterXML/woodstox, skonfiguruj parser StAX, aby sprawdzał poprawność schematu i analizował XML.
Jeśli wyjątki zostaną przechwycone, XML nie jest prawidłowy, w przeciwnym razie jest prawidłowy:
// 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, powinieneś spróbować ponownie użyć
XMLInputFactory
i
XMLValidationSchema
, aby zmaksymalizować wydajność.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Musiałem tylko raz zweryfikować XML pod kątem XSD, więc wypróbowałem XMLFox. Wydało mi się to bardzo zagmatwane i dziwne. Wydaje się, że instrukcje referencyjne nie pasują do interfejsu.
Skończyło się na tym, że korzystałem z LiquidXML Studio 2008 (v6), które było dużo łatwiejsze w użyciu i od razu znajome (interfejs użytkownika jest bardzo podobny do Visual Basic 2008 Express, z którego często korzystam). Wada: w darmowej wersji nie ma opcji walidacji, więc musiałem skorzystać z 30-dniowej wersji próbnej.

Aby odpowiedzieć na pytania, Zaloguj się lub Zarejestruj się