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 : "";
}
}