Jawaban:
Pustaka runtime Java mendukung validasi. Terakhir kali saya memeriksa ini adalah parser Apache Xerces di bawah selimut. Anda mungkin harus menggunakan 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) {}
Konstanta pabrik skema adalah string http://www.w3.org/2001/XMLSchema
yang mendefinisikan XSD. Kode di atas memvalidasi deskriptor penyebaran WAR terhadap URL http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd
tetapi Anda bisa dengan mudah memvalidasi terhadap file lokal.
Anda tidak boleh menggunakan DOMParser untuk memvalidasi dokumen (kecuali jika tujuan Anda adalah membuat model objek dokumen). Ini akan mulai membuat objek DOM karena mem-parsing dokumen - boros jika Anda tidak akan menggunakannya.
Berikut cara melakukannya menggunakan Xerces2 . Tutorial untuk ini, di sini (daftar persyaratan).
Atribusi asli: disalin secara terang-terangan dari sini :
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.");
}
}
}
Kami membangun proyek kami menggunakan semut, sehingga kami dapat menggunakan tugas schemavalidate untuk memeriksa file konfigurasi kami:
<schemavalidate>
<fileset dir="${configdir}" includes="**/*.xml" />
</schemavalidate>
Sekarang file konfigurasi nakal akan gagal membangun kita!
Karena ini adalah pertanyaan yang populer, saya akan menunjukkan bahwa java juga dapat memvalidasi terhadap xsd "dirujuk", misalnya jika file .xml sendiri menentukan XSD di header, menggunakan xsi:SchemaLocation
atau xsi:noNamespaceSchemaLocation
(atau xsi untuk ruang nama tertentu) ex :
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.example.com/document.xsd">
...
atau SchemaLocation (selalu daftar namespace ke pemetaan 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">
...
Jawaban lain juga berfungsi di sini, karena file .xsd "memetakan" ke ruang nama yang dinyatakan dalam file .xml, karena mereka mendeklarasikan namespace, dan jika cocok dengan namespace dalam file .xml, Anda baik. Namun terkadang lebih mudah untuk memiliki penyelesai khusus ...
Dari javadocs: "Jika Anda membuat skema tanpa menentukan URL, file, atau sumber, maka bahasa Java membuat yang terlihat dalam dokumen yang divalidasi untuk menemukan skema yang harus digunakan. Misalnya:"
SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
Schema schema = factory.newSchema();
dan ini berfungsi untuk banyak namespaces, dll. Masalah dengan pendekatan ini adalah bahwa xmlsns:xsi
itu mungkin lokasi jaringan, jadi secara default akan keluar dan tekan jaringan dengan masing-masing dan setiap validasi, tidak selalu optimal.
Berikut ini contoh yang memvalidasi file XML terhadap referensi XSD apa pun (bahkan jika harus menariknya dari jaringan):
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);
}
}
Anda dapat menghindari menarik XSD yang dirujuk dari jaringan, meskipun url referensi file xml, dengan menentukan xsd secara manual (lihat beberapa jawaban lain di sini) atau dengan menggunakan pemecah gaya "Katalog XML" . Spring tampaknya juga dapat mencegat permintaan URL untuk melayani file lokal untuk validasi. Atau Anda dapat mengatur sendiri melalui setResourceResolver , mis:
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);
Lihat juga di sini untuk tutorial lainnya.
Saya percaya standarnya adalah dengan menggunakan parsing DOM, Anda dapat melakukan sesuatu yang mirip dengan parser SAX yang memvalidasi juga saxReader.setEntityResolver(your_resolver_here);
setResourceResolver
tetapi di luar itu, mungkin membuka pertanyaan baru ...
Menggunakan Java 7 Anda dapat mengikuti dokumentasi yang disediakan dalam deskripsi paket .
// 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! }
parser.parse(new File("instance.xml"))
. The validator
menerima Source
, sehingga Anda dapat: validator.validate(new StreamSource(new File("instance.xml")))
.
ErrorHandler
jika Anda perlu melakukan validasi.
Jika Anda memiliki Mesin Linux, Anda dapat menggunakan alat baris perintah SAXCount gratis. Saya menemukan ini sangat berguna.
SAXCount -f -s -n my.xml
Ini memvalidasi terhadap dtd dan xsd. 5s untuk file 50MB.
Dalam debian squeeze terletak di paket "libxerces-c-samples".
Definisi dtd dan xsd harus dalam xml! Anda tidak dapat mengonfigurasinya secara terpisah.
xmllint --schema phone.xsd phone.xml
(dari jawaban oleh 13ren)
Satu jawaban lagi: karena Anda mengatakan Anda perlu memvalidasi file yang Anda hasilkan (menulis), Anda mungkin ingin memvalidasi konten saat Anda menulis, alih-alih menulis terlebih dahulu, lalu membaca kembali untuk validasi. Anda mungkin dapat melakukannya dengan JDK API untuk validasi Xml, jika Anda menggunakan penulis berbasis SAX: jika demikian, cukup tautkan dalam validator dengan memanggil 'Validator.validate (sumber, hasil)', di mana sumber berasal dari penulis Anda, dan hasilnya adalah di mana output harus pergi.
Atau jika Anda menggunakan Stax untuk menulis konten (atau perpustakaan yang menggunakan atau dapat menggunakan stax), Woodstox juga dapat langsung mendukung validasi saat menggunakan XMLStreamWriter. Berikut ini entri blog yang menunjukkan bagaimana hal itu dilakukan:
Jika Anda membuat file XML secara terprogram, Anda mungkin ingin melihat perpustakaan XMLBeans . Menggunakan alat baris perintah, XMLBeans akan secara otomatis menghasilkan dan mengemas satu set objek Java berdasarkan XSD. Anda kemudian dapat menggunakan objek-objek ini untuk membangun dokumen XML berdasarkan skema ini.
Ini memiliki dukungan bawaan untuk validasi skema, dan dapat mengonversi objek Java ke dokumen XML dan sebaliknya.
Castor dan JAXB adalah perpustakaan Java lain yang memiliki tujuan yang mirip dengan XMLBeans.
Dengan JAXB, Anda dapat menggunakan kode di bawah ini:
@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
}
}
Apakah Anda mencari alat atau perpustakaan?
Sejauh perpustakaan berjalan, standar de-facto cukup banyak adalah Xerces2 yang memiliki kedua versi C ++ dan Java .
Sebelum diperingatkan, itu adalah solusi berat. Tetapi sekali lagi, memvalidasi XML terhadap file XSD adalah masalah berat yang agak berat.
Adapun alat untuk melakukan ini untuk Anda, XMLFox tampaknya menjadi solusi freeware yang layak, tetapi tidak menggunakannya secara pribadi saya tidak bisa mengatakan dengan pasti.
Validasi terhadap skema 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);
Validasi terhadap skema lokal
Menggunakan Woodstox , konfigurasikan pengurai StAX untuk memvalidasi terhadap skema Anda dan parsing XML.
Jika pengecualian tertangkap XML tidak valid, jika tidak maka valid:
// 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();
}
Catatan : Jika Anda perlu memvalidasi banyak file, Anda harus mencoba untuk menggunakan kembali XMLInputFactory
dan XMLValidationSchema
untuk memaksimalkan kinerja.
Saya harus memvalidasi XML terhadap XSD hanya satu kali, jadi saya mencoba XMLFox. Saya menemukan itu sangat membingungkan dan aneh. Instruksi bantuan sepertinya tidak cocok dengan antarmuka.
Saya akhirnya menggunakan LiquidXML Studio 2008 (v6) yang jauh lebih mudah digunakan dan lebih akrab (UI sangat mirip dengan Visual Basic 2008 Express, yang sering saya gunakan). Kekurangannya: kemampuan validasi tidak dalam versi gratis, jadi saya harus menggunakan uji coba 30 hari.