Sto provando a convertire del codice dall'utilizzo di DOM (tramite jDOM) per utilizzare invece StAX. Allo stesso tempo sto migrando dalla convalida basata su DTD alla convalida basata su XSD. Oh, e solo per buona misura sto introducendo JAXB nell'equazione :)Stax e spazi dei nomi
In ogni caso, come passaggio di migrazione provvisorio vorrei consentire agli utenti di fornire ancora documenti legacy (ovvero, utilizzando DTD e quindi nessuno spazio dei nomi). Continuerò a convalidare il documento usando XSD, quindi il DTD viene ignorato. Questo funziona eccetto che a StAX (e JAXB) sembra non piacere il documento non assegnato a un nome. Ho provato a disattivare il supporto per lo spazio dei nomi (usando javax.xml.stream.isNamespaceAware), ma ciò non ha avuto alcun effetto. L'aggiunta esplicita di xmlns alla radice del documento ha risolto il problema, quindi sono abbastanza fiducioso che si tratti di un problema di namespacing.
C'è un modo per utilizzare StAX XMLEventReader per "introdurre" uno spazio dei nomi predefinito? Qualcosa sulla falsariga di this approach (che è specifico per SAX), ma per StAX ...
O altre idee su come ottenerlo?
Un documento di esempio appare come:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.test.abstractembeddedcomponents.cid">
...
</hibernate-mapping>
Il codice Attualmente sto usando per leggere questi documenti è:
public JaxbRoot unmarshal(InputStream stream, Origin origin) {
try {
XMLEventReader staxReader = staxFactory().createXMLEventReader(stream);
try {
return unmarshal(staxReader, origin);
}
finally {
try {
staxReader.close();
}
catch (Exception ignore) {
}
}
}
catch (XMLStreamException e) {
throw new MappingException("Unable to create stax reader", e, origin);
}
}
private XMLInputFactory staxFactory;
private XMLInputFactory staxFactory() {
if (staxFactory == null) {
staxFactory = buildStaxFactory();
}
return staxFactory;
}
@SuppressWarnings({ "UnnecessaryLocalVariable" })
private XMLInputFactory buildStaxFactory() {
XMLInputFactory staxFactory = XMLInputFactory.newInstance();
// tried with and without, no effect
//staxFactory.setProperty("javax.xml.stream.isNamespaceAware", false);
return staxFactory;
}
@SuppressWarnings({ "unchecked" })
private JaxbRoot unmarshal(XMLEventReader staxEventReader, final Origin origin) {
XMLEvent event;
try {
event = staxEventReader.peek();
while (event != null && !event.isStartElement()) {
staxEventReader.nextEvent();
event = staxEventReader.peek();
}
}
catch (Exception e) {
throw new MappingException("Error accessing stax stream", e, origin);
}
if (event == null) {
throw new MappingException("Could not locate root element", origin);
}
final Schema validationSchema;
final Class jaxbTarget;
final String elementName = event.asStartElement().getName().getLocalPart();
if ("entity-mappings".equals(elementName)) {
final Attribute attribute = event.asStartElement().getAttributeByName(ORM_VERSION_ATTRIBUTE_QNAME);
final String explicitVersion = attribute == null ? null : attribute.getValue();
validationSchema = validateXml ? resolveSupportedOrmXsd(explicitVersion) : null;
jaxbTarget = JaxbEntityMappings.class;
}
else {
validationSchema = validateXml ? hbmSchema() : null;
jaxbTarget = JaxbHibernateMapping.class;
}
final Object target;
final ContextProvidingValidationEventHandler handler = new ContextProvidingValidationEventHandler();
try {
JAXBContext jaxbContext = JAXBContext.newInstance(jaxbTarget);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
unmarshaller.setSchema(validationSchema);
unmarshaller.setEventHandler(handler);
target = unmarshaller.unmarshal(staxEventReader);
}
catch (JAXBException e) {
throw new MappingException(...);
}
return new JaxbRoot(target, origin);
}
Nel mio test DTD essere lì o non ha alcun effetto. E come ho detto prima, semplicemente cambiando
<hibernate-mapping package="org.hibernate.test.abstractembeddedcomponents.cid">
a
<hibernate-mapping xmlns="http://www.hibernate.org/xsd/hibernate-mapping" package="org.hibernate.test.abstractembeddedcomponents.cid">
correzioni dei guasti che vedo, che sono:
[org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration of element 'hibernate-mapping'.]
at ...
Caused by: org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration of element 'hibernate-mapping'.
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:195)
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:131)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:384)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:318)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleStartElement(XMLSchemaValidator.java:1916)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.startElement(XMLSchemaValidator.java:705)
at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorHandlerImpl.startElement(ValidatorHandlerImpl.java:550)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.ValidatingUnmarshaller.startElement(ValidatingUnmarshaller.java:78)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.InterningXmlVisitor.startElement(InterningXmlVisitor.java:60)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.StAXEventConnector.handleStartElement(StAXEventConnector.java:247)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.StAXEventConnector.bridge(StAXEventConnector.java:116)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:394)
... 27 more
Quale implementazione di StaX? Incorporato JDK? Woodstox? Altro? – bmargulies
JDK integrato credo. Non sto facendo nulla di speciale per configurarne un altro. –
Le persone usano stax per leggere documenti senza spazi dei nomi in ogni momento. Devi mostrarci un po 'di codice e un po' di XML. – bmargulies