Прежде всего, несколько советов. Вам не нужно создавать документ DOM только для проверки. Это приводит к большим затратам памяти, возможно, даже к исчерпанию больших входных XML-документов. Вы можете просто использовать SAXParser
. Если вы используете Java 1.5 или более позднюю версию, это даже не обязательно. С этой версии API проверки XML был включен в Java SE. Проверьте пакет javax.xml.validation для получения дополнительной информации. Идея состоит в том, что вы сначала создаете объект Schema
, а затем получаете Validator
из того, что можно использовать для проверки. Он принимает любую Source
реализацию для ввода. Валидаторам также можно дать ErrorHandlers
, так что вы можете просто повторно использовать свой класс. Конечно, возможно, что вам на самом деле понадобится DOM, но в этом случае все же лучше сделать экземпляр Schema
и зарегистрировать его в своем DocumentBuilderFactory
.
Теперь для актуальной проблемы. Это не совсем легко, так как SAXParseException
не предоставляет вам много контекстной информации. Лучше всего подключить ContentHandler
где-нибудь и следить за тем, в каком элементе вы находитесь, или какой-либо другой позиционной информацией. Затем вы можете передать это обработчику ошибок, когда это необходимо. Класс DefaultHandler
или DefaultHandler2
- это удобный способ сочетания обработки ошибок и содержимого. Вы найдете эти классы в пакете org.xml.sax.ext.
Я собрал тест, который опубликую ниже. Теперь я получаю две строки вывода вместо ожидаемой. Если это происходит из-за того, что я использую схему или я не выкидываю исключение и продолжаю обработку, я не уверен. Вторая строка содержит имя элемента, так что этого может быть достаточно. Вы могли бы установить некоторый флаг на ошибки вместо того, чтобы генерировать исключение и заканчивать анализ.
package jaxb.test;
import java.io.StringReader;
import javax.xml.XMLConstants;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
public class ValidationTest {
public static void main(String[] args) throws Exception {
//Test XML and schema
final String xml = "<?xml version=\"1.0\"?><test><test2></test2></test>";
final String schemaString =
"<?xml version=\"1.0\"?>"
+ "<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" elementFormDefault=\"unqualified\" attributeFormDefault=\"unqualified\">"
+ "<xsd:element name=\"test\" type=\"Test\"/>"
+ "<xsd:element name=\"test2\" type=\"Test2\"/>"
+ "<xsd:complexType name=\"Test\">"
+ "<xsd:sequence>"
+ "<xsd:element ref=\"test2\" minOccurs=\"1\" maxOccurs=\"unbounded\"/>"
+ "</xsd:sequence>"
+ "</xsd:complexType>"
+ "<xsd:simpleType name=\"Test2\">"
+ "<xsd:restriction base=\"xsd:string\"><xsd:minLength value=\"1\"/></xsd:restriction>"
+ "</xsd:simpleType>"
+ "</xsd:schema>";
//Building a Schema instance
final Source schemaSource =
new StreamSource(new StringReader(schemaString));
final Schema schema =
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(schemaSource);
//Creating a SAXParser for our input XML
//First the factory
final SAXParserFactory factory = SAXParserFactory.newInstance();
//Must be namespace aware to receive element names
factory.setNamespaceAware(true);
//Setting the Schema for validation
factory.setSchema(schema);
//Now the parser itself
final SAXParser parser = factory.newSAXParser();
//Creating an instance of our special handler
final MyContentHandler handler = new MyContentHandler();
//Parsing
parser.parse(new InputSource(new StringReader(xml)), handler);
}
private static class MyContentHandler extends DefaultHandler {
private String element = "";
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if(localName != null && !localName.isEmpty())
element = localName;
else
element = qName;
}
@Override
public void warning(SAXParseException exception) throws SAXException {
System.out.println(element + ": " + exception.getMessage());
}
@Override
public void error(SAXParseException exception) throws SAXException {
System.out.println(element + ": " + exception.getMessage());
}
@Override
public void fatalError(SAXParseException exception) throws SAXException {
System.out.println(element + ": " + exception.getMessage());
}
public String getElement() {
return element;
}
}
}
Это немного грубо, но вы можете поработать над этим, чтобы получить то, что вам нужно.