In case anyone is interested, I've posted the code we're using below in case
it's useful:
public class JAXBUtil
{
private JAXBUtil()
{
}
public static void filterNamespaces(ByteArrayInputStream inputStream,
OutputStream outputStream)
throws SAXException, IOException, TransformerConfigurationException
{
// Parsing, removing the uris that haven't been declared
SAXTransformerFactory factory = (SAXTransformerFactory)
TransformerFactory.newInstance();
TransformerHandler transformerHandler = factory.newTransformerHandler();
transformerHandler.setResult(new StreamResult(outputStream));
transformerHandler.getTransformer().setOutputProperty(OutputKeys.INDENT,
"yes");
transformerHandler.getTransformer().setOutputProperty(OutputKeys.ENCODING,
"utf-8");
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
FilterNamespaces filterNamespaces = new
FilterNamespaces(transformerHandler);
xmlReader.setContentHandler(filterNamespaces);
xmlReader.parse(new InputSource(inputStream));
}
private static class FilterNamespaces extends DefaultHandler
{
private static final String SCHEMA_INSTANCE_URI = "
http://www.w3.org/2001/XMLSchema-instance";
private final ContentHandler nextHandler;
private final Map<String, String> uriByPrefix = new HashMap<String,
String>();
private final Map<String, String> prefixByUri = new HashMap<String,
String>();
private final Set<String> registeredUris = new HashSet<String>();
private int depth = 0;
private final List<Set<String>> registeredByDepth = new
ArrayList<Set<String>>();
private FilterNamespaces(ContentHandler nextHandler)
{
this.nextHandler = nextHandler;
}
@Override
public void setDocumentLocator(Locator locator)
{
nextHandler.setDocumentLocator(locator);
}
@Override
public void startDocument() throws SAXException
{
nextHandler.startDocument();
}
@Override
public void endDocument() throws SAXException
{
nextHandler.endDocument();
}
@Override
public void startPrefixMapping(String prefix, String uri) throws
SAXException
{
uriByPrefix.put(prefix, uri);
prefixByUri.put(uri, prefix);
}
@Override
public void endPrefixMapping(String prefix) throws SAXException
{
String uri = uriByPrefix.get(prefix);
uriByPrefix.remove(prefix);
prefixByUri.remove(uri);
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException
{
registeredByDepth.add(new HashSet<String>());
registerNamespace(uri);
for (int i = 0 ; i < attributes.getLength(); i++)
{
String attributeUri = attributes.getURI(i);
registerNamespace(attributeUri);
if (SCHEMA_INSTANCE_URI.equals(attributeUri) &&
"type".equals(attributes.getLocalName(i)))
{
String value = attributes.getValue(i);
int index = value.indexOf(':');
if (index != -1)
{
String prefix = value.substring(0, index);
registerNamespace(uriByPrefix.get(prefix));
}
}
}
nextHandler.startElement(uri, localName, qName, attributes);
depth++;
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException
{
nextHandler.endElement(uri, localName, qName);
depth--;
Set<String> registered = registeredByDepth.remove(depth);
for (String namespace : registered)
{
nextHandler.endPrefixMapping(prefixByUri.get(namespace));
registeredUris.remove(namespace);
}
}
@Override
public void characters(char ch[], int start, int length) throws
SAXException
{
nextHandler.characters(ch, start, length);
}
@Override
public void ignorableWhitespace(char ch[], int start, int length) throws
SAXException
{
nextHandler.ignorableWhitespace(ch, start, length);
}
@Override
public void processingInstruction(String target, String data) throws
SAXException
{
nextHandler.processingInstruction(target, data);
}
@Override
public void skippedEntity(String name) throws SAXException
{
nextHandler.skippedEntity(name);
}
private void registerNamespace(String uri) throws SAXException
{
if ((uri.length() > 0) && !registeredUris.contains(uri))
{
String prefix = prefixByUri.get(uri);
nextHandler.startPrefixMapping(prefix, uri);
registeredUris.add(uri);
registeredByDepth.get(depth).add(uri);
}
}
}
}