Odpowiedzi:
Biblioteka środowiska wykonawczego Java obsługuje sprawdzanie poprawności. Ostatnim razem, gdy sprawdziłem, był to parser Apache Xerces pod przykryciem. Prawdopodobnie powinieneś użyć 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) {}
Stała fabryczna schematu to ciąg znaków, http://www.w3.org/2001/XMLSchema
który definiuje XSD. Powyższy kod weryfikuje deskryptor wdrażania WAR względem adresu URLhttp://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd
ale równie dobrze można zweryfikować względem pliku lokalnego.
Nie powinieneś używać DOMParser do sprawdzania poprawności dokumentu (chyba że Twoim celem jest utworzenie modelu obiektu dokumentu i tak). Rozpocznie się tworzenie obiektów DOM podczas analizy dokumentu - marnotrawstwo, jeśli nie zamierzasz ich używać.
Oto jak to zrobić za pomocą Xerces2 . Samouczek na ten temat tutaj (wymagana rejestracja).
Oryginalne uznanie autorstwa: rażąco 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("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.");
}
}
}
Nasz projekt budujemy za pomocą ant, dzięki czemu możemy użyć zadania schemavalidate do sprawdzenia plików konfiguracyjnych:
<schemavalidate>
<fileset dir="${configdir}" includes="**/*.xml" />
</schemavalidate>
Teraz niegrzeczne pliki konfiguracyjne zakończą się niepowodzeniem!
Ponieważ jest to popularne pytanie, zwrócę uwagę, że java może również sprawdzać poprawność względem „odesłanego” xsd, na przykład jeśli sam plik .xml określa XSD w nagłówku, używając xsi:SchemaLocation
lub xsi:noNamespaceSchemaLocation
(lub xsi dla określonych przestrzeni nazw) np . :
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.example.com/document.xsd">
...
lub SchemaLocation (zawsze lista przestrzeni nazw do odwzorowań 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">
...
Tutaj działają również inne odpowiedzi, ponieważ pliki .xsd „mapują” na przestrzenie nazw zadeklarowane w pliku .xml, ponieważ deklarują przestrzeń nazw, a jeśli są zgodne z przestrzenią nazw w pliku .xml, jesteś dobry. Ale czasem wygodnie jest mieć niestandardowy program rozpoznawania nazw ...
Z javadocs: „Jeśli utworzysz schemat bez określania adresu URL, pliku lub źródła, wówczas język Java tworzy taki, który sprawdza dokument w trakcie sprawdzania poprawności w celu znalezienia schematu, którego powinien użyć. Na przykład:”
SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
Schema schema = factory.newSchema();
i działa to w przypadku wielu przestrzeni nazw itp. Problem z tym podejściem polega na tym, że xmlsns:xsi
prawdopodobnie jest to lokalizacja sieciowa, więc domyślnie wychodzi i trafia do sieci przy każdej walidacji, nie zawsze optymalnej.
Oto przykład, który sprawdza poprawność pliku XML względem dowolnych plików XSD, do których się odwołuje (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("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żna uniknąć ciągnięcia odwołań XSD z sieci, nawet jeśli pliki xml odwołują się do adresów URL, poprzez ręczne określenie xsd (zobacz kilka innych odpowiedzi tutaj) lub za pomocą resolvera w stylu „katalogu XML” . Wygląda na to, że Spring może również przechwytywać żądania adresów URL w celu udostępniania lokalnych plików do weryfikacji. Lub możesz ustawić własne za pomocą setResourceResolver , np .:
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 także tutaj, aby zapoznać się z innym samouczkiem.
Wierzę domyślnym jest użycie DOM parsowania, można zrobić coś podobnego z parsera SAX, który jest zatwierdzającego oraz saxReader.setEntityResolver(your_resolver_here);
setResourceResolver
ale poza tym, może otwórz nowe pytanie ...
Za pomocą Java 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! }
parser.parse(new File("instance.xml"))
. validator
Akceptuje Source
, więc można: validator.validate(new StreamSource(new File("instance.xml")))
.
ErrorHandler
jeśli konieczne jest sprawdzenie poprawności.
Jeśli masz maszynę z systemem Linux, możesz skorzystać z bezpłatnego narzędzia wiersza polecenia SAXCount. Uważam to za bardzo przydatne.
SAXCount -f -s -n my.xml
Sprawdza się względem dtd i xsd. 5s dla pliku 50 MB.
W debian squeeze znajduje się w pakiecie „libxerces-c-samples”.
Definicja dtd i xsd musi znajdować się w xml! Nie można ich konfigurować osobno.
xmllint --schema phone.xsd phone.xml
(z odpowiedzi 13ren)
Jeszcze jedna odpowiedź: skoro powiedziałeś, że musisz sprawdzić poprawność generowanych plików (piszesz), możesz chcieć sprawdzić poprawność treści podczas pisania, zamiast najpierw pisać, a potem czytać w celu sprawdzenia poprawności. Prawdopodobnie możesz to zrobić za pomocą JDK API do sprawdzania poprawności Xml, jeśli używasz programu piszącego opartego na SAX: jeśli tak, po prostu połącz w walidatorze, wywołując „Validator.validate (źródło, wynik)”, gdzie źródło pochodzi od twojego pisarza, a wynikiem jest gdzie wyjście musi iść.
Alternatywnie, jeśli używasz Stax do pisania treści (lub biblioteki, która używa lub może używać stax), Woodstox może również bezpośrednio obsługiwać sprawdzanie poprawności przy użyciu XMLStreamWriter. Oto wpis na blogu pokazujący, jak to zrobić:
Jeśli programowo generujesz pliki XML, możesz zajrzeć do biblioteki XMLBeans . Za pomocą narzędzia wiersza poleceń XMLBeans automatycznie wygeneruje i spakuje zestaw obiektów Java na podstawie XSD. Następnie można użyć tych obiektów do zbudowania dokumentu XML na podstawie tego schematu.
Ma wbudowaną obsługę sprawdzania poprawności schematu i może konwertować obiekty Java na dokument XML i odwrotnie.
Castor i JAXB to inne biblioteki Java, które służą podobnym celom jak XMLBeans.
Dzięki 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
}
}
Szukasz narzędzia lub biblioteki?
Jeśli chodzi o biblioteki, de facto standardem jest Xerces2, który ma zarówno wersje C ++, jak i Java .
Ostrzegam jednak, że jest to rozwiązanie ciężkie. Ale z drugiej strony sprawdzanie poprawności XML względem plików XSD jest dość dużym problemem.
Jeśli chodzi o narzędzie do zrobienia tego dla ciebie, XMLFox wydaje się być przyzwoitym darmowym rozwiązaniem, ale nie użyłem go osobiście, nie mogę powiedzieć na pewno.
Sprawdź poprawność pod kątem schematów 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);
Sprawdź poprawność względem lokalnych schematów
Za pomocą Woodstox skonfiguruj analizator składni StAX, aby sprawdzić poprawność względem schematu i przeanalizuj XML.
Jeśli wychwycone zostaną wyjątki, kod XML jest niepoprawny, 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 musisz sprawdzić poprawność wielu plików, powinieneś spróbować ponownie użyć swojego XMLInputFactory
i XMLValidationSchema
, aby zmaksymalizować wydajność.
Musiałem tylko raz sprawdzić XML względem XSD, więc wypróbowałem XMLFox. Uważam, że jest to bardzo mylące i dziwne. Wydawało się, że instrukcje pomocy nie pasują do interfejsu.
Skończyło się na użyciu LiquidXML Studio 2008 (v6), które było znacznie łatwiejsze w użyciu i od razu bardziej znane (interfejs użytkownika jest bardzo podobny do Visual Basic 2008 Express, z którego często korzystam). Wada: funkcja sprawdzania poprawności nie jest dostępna w wersji bezpłatnej, więc musiałem skorzystać z 30-dniowej wersji próbnej.