Dear Christian,
thank you for quickly attacking the problem! But sorry, but the problem is not fixed.I get the same error.
I have a general note.
I have implemented a special serializer which implements org.xml.sax .XMLReader. This is used to directly dispatch the query result to JAXB and to created objects. I can now extend this technique to generate a new DOM by implementing a SAX ContentHandler which generates a DOM.
Unfortunately the serializer API is not documented nor stable (it changed from 7.3 to 7.5). I propose to add a standard SAX serializer to BaseX. This would be a very useful extension.
Here is my implementation:
import static org.basex.util.Token.XMLNS; import static org.basex.util.Token.startsWith; import static org.basex.util.Token.string; import static org.basex.util.Token.substring;
import java.io.IOException; import java.util.HashMap; import java.util.Map;
import org.basex.io.serial.Serializer; import org.basex.query.value.item.Item; import org.xml.sax.ContentHandler; import org.xml.sax.DTDHandler; import org.xml.sax.EntityResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; import org.xml.sax.XMLReader; import org.xml.sax.ext.LexicalHandler; import org.xml.sax.helpers.AttributesImpl;
/** * Bridge to translate BaseX items to SAX events. * The parse() methods does the following: * <ol> * <li>notify startDocument()</li> * <li>serialize the item</li> * <li>notify endDocument()</li> */ public class FragmentSerializer extends Serializer implements XMLReader { /** * The item to be serialized */ private Item item;
private ContentHandler contentHandler; private EntityResolver entityResolver; private DTDHandler dtdHandler; private ErrorHandler errorHandler; private LexicalHandler lexicalHandler;
public FragmentSerializer() { }
public Item getItem() { return item; }
/** * Sets the item to be serialized. */ public void setItem(Item item) { this.item = item; }
////////////////////////////////////////////////// // XMLReader //////////////////////////////////////////////////
@Override public ContentHandler getContentHandler() { return contentHandler; }
@Override public boolean getFeature(final String name) { return false; }
@Override public Object getProperty(final String name) { return null; }
public void parse() throws SAXException { parse(""); }
@Override public void parse(final InputSource input) throws SAXException { parse(""); }
@Override public void parse(final String id) throws SAXException { try { contentHandler.startDocument(); item.serialize(this); contentHandler.endDocument(); } catch (final Exception ex) { throw new SAXException(ex); } }
@Override public void setContentHandler(final ContentHandler c) { contentHandler = c; }
public void setLexicalHandler(final LexicalHandler l) { lexicalHandler = l; }
@Override public void setEntityResolver(EntityResolver entityResolver) { this.entityResolver = entityResolver; }
@Override public EntityResolver getEntityResolver() { return entityResolver; }
@Override public void setDTDHandler(DTDHandler dtdHandler) { this.dtdHandler = dtdHandler; }
@Override public DTDHandler getDTDHandler() { return dtdHandler; }
@Override public void setErrorHandler(ErrorHandler errorHandler) { this.errorHandler = errorHandler; }
@Override public ErrorHandler getErrorHandler() { return errorHandler; }
@Override public void setFeature(final String name, final boolean value) throws SAXNotRecognizedException, SAXNotSupportedException { throw new SAXNotRecognizedException(); }
@Override public void setProperty(final String name, final Object value) throws SAXNotRecognizedException, SAXNotSupportedException { throw new SAXNotRecognizedException(); }
////////////////////////////////////////////////// // Serializer //////////////////////////////////////////////////
private final HashMap<String, String> attributes = new HashMap<String, String>(); private NSDecl namespaces;
@Override protected void startOpen(byte[] n) throws IOException { attributes.clear(); this.namespaces = new NSDecl(this.namespaces); }
@Override protected void attribute(byte[] n, byte[] v) throws IOException { String value = string(v);
String prefix = null; if (startsWith(n, XMLNS)) { if (n.length == 5) { prefix = ""; } else if (n[5] == ':') { prefix = string(substring(n, 6)); } }
if (prefix != null) { namespaces.put(prefix, value); } else { String name = string(n); attributes.put(name, value); } }
@Override protected void finishOpen() throws IOException { try { AttributesImpl attrs = new AttributesImpl(); for (Map.Entry<String, String> e : attributes.entrySet()) { String rname = e.getKey(); String[] qname = qname(rname); String ns = namespaces.get(qname[0]); String lname = qname[1]; attrs.addAttribute(ns, lname, rname, null, e.getValue()); }
String rname = string(elem); String[] qname = qname(rname); String ns = namespaces.get(qname[0]); String lname = qname[1]; contentHandler.startElement(ns, lname, rname, attrs);
// System.out.println("{" + ns + "}" + lname); // for (int i = 0; i < attrs.getLength(); i++) // { // System.out.println(" {" + attrs.getURI(i) + "}" + attrs.getLocalName(i) + "=" + attrs.getValue(i)); // } } catch (final SAXException e) { throw new IOException(e.getMessage()); } }
public String[] qname(String rname) { String prefix = ""; String lname = rname;
int i = rname.indexOf(':'); if (i > 0) { prefix = rname.substring(0, i); lname = rname.substring(i + 1); } return new String[] { prefix, lname }; }
@Override protected void finishEmpty() throws IOException { finishOpen(); finishClose(); }
@Override protected void finishClose() throws IOException { try { String name = string(elem); contentHandler.endElement("", name, name); this.namespaces = namespaces.getParent(); } catch (final SAXException e) { throw new IOException(e.getMessage()); } }
@Override protected void finishText(byte[] text) throws IOException { try { String s = string(text); final char[] c = s.toCharArray(); contentHandler.characters(c, 0, c.length); } catch (final SAXException e) { throw new IOException(e.getMessage()); } }
@Override protected void finishComment(byte[] comment) throws IOException { if (lexicalHandler != null) { try { String s = string(comment); final char[] c = s.toCharArray(); lexicalHandler.comment(c, 0, c.length); } catch (final SAXException e) { throw new IOException(e.getMessage()); } } }
@Override protected void finishPi(byte[] n, byte[] v) throws IOException { //ignored }
@Override protected void atomic(Item i) throws IOException { //ignored } }
class NSDecl { private final NSDecl parent; private Map<String, String> decls;
public NSDecl(NSDecl parent) { this.parent = parent; }
public NSDecl getParent() { return parent; }
public void put(String prefix, String uri) { if (decls == null) { decls = new HashMap<String, String>(); } decls.put(prefix, uri); }
public String get(String prefix) { String ns = null; for (NSDecl c = this; c != null; c = c.parent) { if (c.decls != null) { ns = c.decls.get(prefix); if (ns != null) { break; } } } return ns != null ? ns : ""; } }