Antworten:
Die Java-Laufzeitbibliothek unterstützt die Validierung. Als ich das letzte Mal nachgesehen habe, war dies der Apache Xerces-Parser unter der Decke. Sie sollten wahrscheinlich einen javax.xml.validation.Validator verwenden .
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) {}
Die Schema-Factory-Konstante ist die Zeichenfolge, http://www.w3.org/2001/XMLSchema
die XSDs definiert. Der obige Code validiert einen WAR-Bereitstellungsdeskriptor anhand der URL. http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd
Sie können ihn jedoch genauso einfach anhand einer lokalen Datei validieren.
Sie sollten den DOMParser nicht zum Validieren eines Dokuments verwenden (es sei denn, Sie möchten ohnehin ein Dokumentobjektmodell erstellen). Dadurch werden DOM-Objekte erstellt, während das Dokument analysiert wird - verschwenderisch, wenn Sie sie nicht verwenden.
Hier erfahren Sie, wie Sie dies mit Xerces2 tun . Ein Tutorial dazu hier (Anmeldung erforderlich).
Ursprüngliche Zuschreibung: offensichtlich von hier kopiert :
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.");
}
}
}
Wir erstellen unser Projekt mit ant, damit wir die Task schemavalidate verwenden können, um unsere Konfigurationsdateien zu überprüfen:
<schemavalidate>
<fileset dir="${configdir}" includes="**/*.xml" />
</schemavalidate>
Jetzt werden freche Konfigurationsdateien unseren Build nicht bestehen!
Da dies eine beliebte Frage ist, werde ich kann , dass Java auch darauf hinweist Validate gegen „bezeichnet“ xsd sind, zum Beispiel , wenn die XML - Datei selbst im Header XSD die angibt, mit xsi:SchemaLocation
oder xsi:noNamespaceSchemaLocation
(oder xsi für bestimmte Namensräume) ab :
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.example.com/document.xsd">
...
oder SchemaLocation (immer eine Liste von Namespace-zu-xsd-Zuordnungen)
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:SchemaLocation="http://www.example.com/my_namespace http://www.example.com/document.xsd">
...
Die anderen Antworten funktionieren auch hier, da die .xsd-Dateien den in der .xml-Datei deklarierten Namespaces "zugeordnet" sind, weil sie einen Namespace deklarieren und wenn Sie mit dem Namespace in der .xml-Datei übereinstimmen, sind Sie gut. Aber manchmal ist es praktisch, einen benutzerdefinierten Resolver zu haben ...
Aus den Javadocs: "Wenn Sie ein Schema erstellen, ohne eine URL, Datei oder Quelle anzugeben, erstellt die Java-Sprache eine, die im zu überprüfenden Dokument nach dem zu verwendenden Schema sucht. Beispiel:"
SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
Schema schema = factory.newSchema();
und das funktioniert für mehrere Namespaces usw. Das Problem bei diesem Ansatz ist, dass xmlsns:xsi
es sich wahrscheinlich um einen Netzwerkspeicherort handelt, sodass er standardmäßig bei jeder Validierung ausgeht und das Netzwerk trifft, was nicht immer optimal ist.
Hier ist ein Beispiel, das eine XML-Datei anhand von XSDs überprüft, auf die sie verweist (auch wenn sie aus dem Netzwerk abgerufen werden muss):
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);
}
}
Sie können vermeiden, referenzierte XSDs aus dem Netzwerk abzurufen, obwohl die XML-Dateien auf URLs verweisen, indem Sie die xsd manuell angeben (siehe einige andere Antworten hier) oder einen Resolver im Stil eines "XML-Katalogs" verwenden . Spring kann anscheinend auch die URL-Anforderungen abfangen , um lokale Dateien für Validierungen bereitzustellen. Oder Sie können Ihre eigenen über setResourceResolver festlegen , z.
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);
Siehe auch hier für ein weiteres Tutorial.
Ich glaube , dass die Standard - DOM - Parsing zu verwenden ist, können Sie etwas ähnliches mit SAX - Parser tun können , das ist die Validierung als auch saxReader.setEntityResolver(your_resolver_here);
setResourceResolver
aber darüber hinaus einstellen , vielleicht öffnen Sie eine neue Frage ...
Mit Java 7 können Sie der Dokumentation in der Paketbeschreibung folgen .
// 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! }
parser.parse(new File("instance.xml"))
. Das validator
akzeptiert a Source
, damit Sie : validator.validate(new StreamSource(new File("instance.xml")))
.
ErrorHandler
wenn Sie eine Validierung durchführen müssen.
Wenn Sie eine Linux-Maschine haben, können Sie das kostenlose Befehlszeilentool SAXCount verwenden. Ich fand das sehr nützlich.
SAXCount -f -s -n my.xml
Es wird gegen dtd und xsd validiert. 5s für eine 50MB Datei.
In Debian Squeeze befindet es sich im Paket "libxerces-c-samples".
Die Definition von dtd und xsd muss in der xml sein! Sie können sie nicht separat konfigurieren.
xmllint --schema phone.xsd phone.xml
(aus einer Antwort von 13ren)
Noch eine Antwort: Da Sie gesagt haben, dass Sie die von Ihnen generierten (schreibenden) Dateien validieren müssen, möchten Sie möglicherweise den Inhalt während des Schreibens validieren, anstatt zuerst zu schreiben und dann zur Validierung zurückzulesen. Sie können dies wahrscheinlich mit der JDK-API für die XML-Validierung tun, wenn Sie einen SAX-basierten Writer verwenden: Wenn ja, verknüpfen Sie den Validator einfach, indem Sie 'Validator.validate (Quelle, Ergebnis)' aufrufen, wobei die Quelle von Ihrem Writer stammt und das Ergebnis ist wohin die Ausgabe gehen muss.
Wenn Sie Stax zum Schreiben von Inhalten verwenden (oder eine Bibliothek, die stax verwendet oder verwenden kann), kann Woodstox die Validierung auch direkt unterstützen, wenn Sie XMLStreamWriter verwenden. Hier ist ein Blogeintrag, der zeigt, wie das gemacht wird:
Wenn Sie XML-Dateien programmgesteuert generieren, sollten Sie sich die XMLBeans- Bibliothek ansehen . Mithilfe eines Befehlszeilentools generiert XMLBeans automatisch eine Reihe von Java-Objekten basierend auf einer XSD und packt sie zusammen. Mit diesen Objekten können Sie dann ein XML-Dokument erstellen, das auf diesem Schema basiert.
Es bietet integrierte Unterstützung für die Schemaüberprüfung und kann Java-Objekte in ein XML-Dokument konvertieren und umgekehrt.
Castor und JAXB sind andere Java-Bibliotheken, die einen ähnlichen Zweck wie XMLBeans erfüllen.
Mit JAXB können Sie den folgenden Code verwenden:
@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
}
}
Suchen Sie ein Tool oder eine Bibliothek?
In Bezug auf Bibliotheken ist Xerces2, das sowohl C ++ als auch Java- Versionen hat , so ziemlich der De-facto-Standard .
Seien Sie jedoch gewarnt, es ist eine schwere Lösung. Andererseits ist die Validierung von XML anhand von XSD-Dateien ein ziemlich schweres Problem.
Als Tool, das dies für Sie erledigt, scheint XMLFox eine anständige Freeware-Lösung zu sein, aber nachdem ich es nicht persönlich verwendet habe, kann ich nicht sicher sagen.
Validieren Sie anhand von Online-Schemas
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);
Überprüfen Sie anhand lokaler Schemas
Konfigurieren Sie mit Woodstox den StAX-Parser so, dass er anhand Ihres Schemas überprüft und das XML analysiert wird.
Wenn Ausnahmen abgefangen werden, ist das XML ungültig, andernfalls ist es gültig:
// 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();
}
Hinweis : Wenn Sie mehrere Dateien validieren müssen, sollten Sie versuchen, Ihre XMLInputFactory
und wiederzuverwenden XMLValidationSchema
, um die Leistung zu maximieren.
Ich musste ein XML nur einmal gegen XSD validieren, also habe ich XMLFox ausprobiert. Ich fand es sehr verwirrend und seltsam. Die Hilfeanweisungen schienen nicht mit der Benutzeroberfläche übereinzustimmen.
Am Ende habe ich LiquidXML Studio 2008 (v6) verwendet, das viel einfacher zu verwenden und sofort vertrauter war (die Benutzeroberfläche ist Visual Basic 2008 Express sehr ähnlich, das ich häufig verwende). Der Nachteil: Die Validierungsfunktion ist nicht in der kostenlosen Version enthalten, daher musste ich die 30-Tage-Testversion verwenden.