Câu trả lời:
Thư viện thời gian chạy Java hỗ trợ xác nhận hợp lệ. Lần trước tôi đã kiểm tra đây là trình phân tích cú pháp Apache Xerces dưới vỏ bọc. Có lẽ bạn nên sử dụng một 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) {}
Hằng số nhà máy lược đồ là chuỗi http://www.w3.org/2001/XMLSchema
xác định XSD. Đoạn mã trên xác nhận một mô tả triển khai WAR dựa trên URL http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd
nhưng bạn có thể dễ dàng xác nhận đối với một tệp cục bộ.
Bạn không nên sử dụng DOMParser để xác thực tài liệu (trừ khi mục tiêu của bạn là tạo mô hình đối tượng tài liệu bằng mọi cách). Điều này sẽ bắt đầu tạo các đối tượng DOM vì nó phân tích tài liệu - thật lãng phí nếu bạn không sử dụng chúng.
Đây là cách thực hiện bằng Xerces2 . Một hướng dẫn cho điều này, ở đây (đăng ký lại).
Ghi công gốc: sao chép trắng trợn từ đây :
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.");
}
}
}
Chúng tôi xây dựng dự án của mình bằng ant, vì vậy chúng tôi có thể sử dụng tác vụ schemavalidate để kiểm tra các tệp cấu hình của mình:
<schemavalidate>
<fileset dir="${configdir}" includes="**/*.xml" />
</schemavalidate>
Bây giờ các tập tin cấu hình nghịch ngợm sẽ thất bại trong quá trình xây dựng của chúng tôi!
Vì đây là một câu hỏi phổ biến, tôi sẽ chỉ ra rằng java cũng có thể xác nhận hợp lệ đối với "được đề cập" của xsd, chẳng hạn nếu chính tệp .xml chỉ định XSD trong tiêu đề, sử dụng xsi:SchemaLocation
hoặc xsi:noNamespaceSchemaLocation
(hoặc xsi cho các không gian tên cụ thể) ex :
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.example.com/document.xsd">
...
hoặc SchemaLocation (luôn là danh sách không gian tên cho ánh xạ 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">
...
Các câu trả lời khác cũng hoạt động ở đây, vì các tệp .xsd "ánh xạ" tới các không gian tên được khai báo trong tệp .xml, vì chúng khai báo một không gian tên và nếu khớp với không gian tên trong tệp .xml, thì tốt. Nhưng đôi khi thật tiện lợi khi có thể có trình phân giải tùy chỉnh ...
Từ javadocs: "Nếu bạn tạo một lược đồ mà không chỉ định URL, tệp hoặc nguồn, thì ngôn ngữ Java sẽ tạo một lược đồ trong tài liệu đang được xác thực để tìm lược đồ mà nó nên sử dụng. Ví dụ:"
SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
Schema schema = factory.newSchema();
và điều này hoạt động cho nhiều không gian tên, v.v. Vấn đề với cách tiếp cận này xmlsns:xsi
là có lẽ là một vị trí mạng, do đó, mặc định nó sẽ đi ra ngoài và truy cập mạng với mỗi xác thực, không phải lúc nào cũng tối ưu.
Đây là một ví dụ xác thực một tệp XML dựa trên bất kỳ XSD nào mà nó tham chiếu (ngay cả khi nó phải kéo chúng ra khỏi mạng):
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);
}
}
Bạn có thể tránh kéo các XSD được tham chiếu khỏi mạng, mặc dù các url tham chiếu tệp xml, bằng cách chỉ định xsd theo cách thủ công (xem một số câu trả lời khác tại đây) hoặc bằng cách sử dụng trình phân giải kiểu "danh mục XML" . Spring rõ ràng cũng có thể chặn các yêu cầu URL để phục vụ các tệp cục bộ để xác thực. Hoặc bạn có thể đặt riêng của mình thông qua setResourceResolver , ví dụ:
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);
Xem thêm ở đây để xem hướng dẫn khác.
Tôi tin mặc định là sử dụng DOM phân tích cú pháp, bạn có thể làm điều gì đó tương tự với SAX phân tích cú pháp được xác nhận cũng saxReader.setEntityResolver(your_resolver_here);
setResourceResolver
nhưng ngoài đó, có thể mở câu hỏi mới ...
Sử dụng Java 7, bạn có thể làm theo tài liệu được cung cấp trong mô tả gói .
// 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"))
. Việc validator
chấp nhận a Source
, vì vậy bạn có thể : validator.validate(new StreamSource(new File("instance.xml")))
.
ErrorHandler
nếu bạn cần xác thực.
Nếu bạn có Linux-Machine, bạn có thể sử dụng công cụ dòng lệnh miễn phí SAXCount. Tôi thấy điều này rất hữu ích.
SAXCount -f -s -n my.xml
Nó xác nhận chống lại dtd và xsd. 5s cho tệp 50MB.
Trong debian bóp nó nằm trong gói "libxerces-c-samples".
Định nghĩa của dtd và xsd phải có trong xml! Bạn không thể cấu hình chúng một cách riêng biệt.
xmllint --schema phone.xsd phone.xml
(từ câu trả lời của 13ren)
Thêm một câu trả lời: vì bạn nói rằng bạn cần xác thực các tệp bạn đang tạo (viết), bạn có thể muốn xác thực nội dung trong khi bạn đang viết, thay vì viết trước, sau đó đọc lại để xác thực. Bạn có thể có thể làm điều đó với xác thực API JDK để xác thực Xml, nếu bạn sử dụng trình soạn thảo dựa trên SAX: nếu vậy, chỉ cần liên kết trong trình xác thực bằng cách gọi 'Validator.validate (nguồn, kết quả)', trong đó nguồn đến từ nhà văn của bạn và kết quả là nơi đầu ra cần phải đi.
Ngoài ra, nếu bạn sử dụng Stax để viết nội dung (hoặc thư viện sử dụng hoặc có thể sử dụng stax), Woodstox cũng có thể hỗ trợ trực tiếp xác thực khi sử dụng XMLStreamWriter. Đây là một mục blog cho thấy làm thế nào được thực hiện:
Nếu bạn đang tạo các tệp XML theo chương trình, bạn có thể muốn xem thư viện XMLBeans . Sử dụng một công cụ dòng lệnh, XMLBeans sẽ tự động tạo và đóng gói một tập hợp các đối tượng Java dựa trên XSD. Sau đó, bạn có thể sử dụng các đối tượng này để xây dựng một tài liệu XML dựa trên lược đồ này.
Nó có hỗ trợ tích hợp để xác thực lược đồ và có thể chuyển đổi các đối tượng Java thành tài liệu XML và ngược lại.
Castor và JAXB là các thư viện Java khác phục vụ mục đích tương tự như XMLBeans.
Với JAXB, bạn có thể sử dụng mã dưới đây:
@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
}
}
Bạn đang tìm kiếm một công cụ hoặc một thư viện?
Theo như các thư viện, khá nhiều tiêu chuẩn thực tế là Xerces2 có cả phiên bản C ++ và Java .
Được cảnh báo trước mặc dù, nó là một giải pháp trọng lượng nặng. Nhưng một lần nữa, việc xác thực XML đối với các tệp XSD là một vấn đề khá nặng nề.
Đối với một công cụ để làm điều này cho bạn, XMLFox dường như là một giải pháp phần mềm miễn phí hợp lý, nhưng tôi không chắc chắn sử dụng nó.
Xác thực đối với các lược đồ trực tuyến
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);
Xác thực đối với các lược đồ địa phương
Sử dụng Woodstox , định cấu hình trình phân tích cú pháp StAX để xác thực theo lược đồ của bạn và phân tích cú pháp XML.
Nếu ngoại lệ bị bắt thì XML không hợp lệ, nếu không thì nó hợp lệ:
// 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();
}
Lưu ý : Nếu bạn cần xác thực nhiều tệp, bạn nên cố gắng sử dụng lại XMLInputFactory
và XMLValidationSchema
để tối đa hóa hiệu suất.
Tôi đã phải xác thực một XML dựa trên XSD chỉ một lần, vì vậy tôi đã thử XMLFox. Tôi thấy nó rất khó hiểu và kỳ lạ. Các hướng dẫn trợ giúp dường như không khớp với giao diện.
Tôi đã kết thúc việc sử dụng LiquidXML Studio 2008 (v6), nó dễ sử dụng hơn và quen thuộc hơn ngay lập tức (giao diện người dùng rất giống với Visual Basic 2008 Express, mà tôi thường sử dụng). Hạn chế: khả năng xác nhận không có trong phiên bản miễn phí, vì vậy tôi đã phải sử dụng bản dùng thử 30 ngày.