/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Emil Ong */ package com.caucho.xml.stream; import static javax.xml.XMLConstants.*; import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; import javax.xml.stream.XMLOutputFactory; import static javax.xml.stream.XMLStreamConstants.*; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamWriter; import java.io.IOException; import java.util.Iterator; import com.caucho.util.L10N; /** * Utility class to do namespace repairs on XMLStreamWriters that don't have * repair enabled. Used by JAXB. **/ public class StaxUtil { public static final L10N L = new L10N(StaxUtil.class); public static QName resolveStringToQName(String string, XMLStreamReader in) throws XMLStreamException { return resolveStringToQName(string, in.getNamespaceContext()); } public static QName resolveStringToQName(String string, NamespaceContext context) throws XMLStreamException { int colon = string.indexOf(':'); if (colon < 0) return new QName(string); if (colon + 1 >= string.length()) throw new XMLStreamException(L.l("Invalid qualified name: {0}", string)); String prefix = string.substring(0, colon); String localName = string.substring(colon + 1); String namespace = context.getNamespaceURI(prefix); if (NULL_NS_URI.equals(namespace)) throw new XMLStreamException(L.l("No namespace for qualifed name: {0}", string)); return new QName(namespace, localName, prefix); } /** * Ensures that a given namespace exists within the namespace context * given. **/ public static void repairNamespace(XMLStreamWriter out, String namespace) throws XMLStreamException { try { Object repairing = out.getProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES); if (Boolean.TRUE.equals(repairing)) return; } catch (IllegalArgumentException e) { } catch (NullPointerException e) { } getNamespacePrefix(out, namespace); } /** * Ensures that a given namespace exists within the namespace context * given and returns the prefix. **/ public static String getNamespacePrefix(XMLStreamWriter out, String namespace) throws XMLStreamException { NamespaceContext context = out.getNamespaceContext(); String prefix = context.getPrefix(namespace); if (prefix != null) return prefix; if (context instanceof NamespaceWriterContext) { NamespaceWriterContext writerContext = (NamespaceWriterContext) context; boolean repair = writerContext.getRepair(); writerContext.setRepair(true); prefix = writerContext.declare(namespace); writerContext.setRepair(repair); return prefix; } else { // not one of ours... // we have to search for a unique prefix... int i = 0; String unique = "ns" + i; while (true) { boolean found = false; Iterator iterator = context.getPrefixes(namespace); while (iterator.hasNext()) { prefix = iterator.next().toString(); if (prefix.equals(unique)) { i++; unique = "ns" + i; found = true; break; } } if (! found) break; } out.writeNamespace(unique, namespace); return unique; } } /** * Ensures that a given prefix->namespace mapping exists within the * namespace context given. **/ public static void repairNamespace(XMLStreamWriter out, String prefix, String namespace) throws XMLStreamException { try { Object repairing = out.getProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES); if (Boolean.TRUE.equals(repairing)) return; } catch (IllegalArgumentException e) { } catch (NullPointerException e) { } NamespaceContext context = out.getNamespaceContext(); String oldPrefix = context.getPrefix(namespace); if (! prefix.equals(oldPrefix)) out.writeNamespace(prefix, namespace); } public static XMLStreamWriter toRepairingXMLStreamWriter(XMLStreamWriter out) { try { Object repairing = out.getProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES); if (Boolean.TRUE.equals(repairing)) return out; } catch (IllegalArgumentException e) { } catch (NullPointerException e) { } if (out instanceof XMLStreamWriterImpl) { ((XMLStreamWriterImpl) out).setRepair(true); return out; } else { return new XMLStreamWriterRepairingWrapper(out); } } /** * Copys all the events from the input to the output, without going past * an unmatch end element. * * E.g.: if the input is at the start of <y>, it will only read just past </y> * * <x> * <y> * <z/> * </y> * </x> * **/ public static void copyReaderToWriter(XMLStreamReader in, XMLStreamWriter out) throws XMLStreamException { int depth = 0; do { switch (in.getEventType()) { case ATTRIBUTE: break; case CDATA: out.writeCData(in.getText()); break; case CHARACTERS: out.writeCharacters(in.getText()); break; case COMMENT: out.writeComment(in.getText()); break; case DTD: out.writeDTD(in.getText()); break; case END_DOCUMENT: out.writeEndDocument(); break; case END_ELEMENT: depth--; if (depth < 0) { out.flush(); return; } out.writeEndElement(); break; case ENTITY_REFERENCE: out.writeEntityRef(in.getText()); break; case NAMESPACE: break; case PROCESSING_INSTRUCTION: out.writeProcessingInstruction(in.getPITarget(), in.getPIData()); break; case SPACE: out.writeCharacters(in.getText()); break; case START_DOCUMENT: out.writeStartDocument(in.getEncoding(), in.getVersion()); break; case START_ELEMENT: QName qname = in.getName(); if (qname.getNamespaceURI() == null || "".equals(qname.getNamespaceURI())) out.writeStartElement(qname.getLocalPart()); else if (qname.getPrefix() == null || "".equals(qname.getPrefix())) out.writeStartElement(qname.getNamespaceURI(), qname.getLocalPart()); else out.writeStartElement(qname.getPrefix(), qname.getLocalPart(), qname.getNamespaceURI()); for (int i = 0; i < in.getAttributeCount(); i++) { qname = in.getAttributeName(i); String value = in.getAttributeValue(i); if (qname.getNamespaceURI() == null || "".equals(qname.getNamespaceURI())) out.writeAttribute(qname.getLocalPart(), value); else if (qname.getPrefix() == null || "".equals(qname.getPrefix())) out.writeAttribute(qname.getNamespaceURI(), qname.getLocalPart(), value); else out.writeAttribute(qname.getPrefix(), qname.getNamespaceURI(), qname.getLocalPart(), value); } for (int i = 0; i < in.getNamespaceCount(); i++) out.writeNamespace(in.getNamespacePrefix(i), in.getNamespaceURI(i)); depth++; break; } if (in.hasNext()) in.next(); else break; } while (depth >= 0); out.flush(); } public static String constantToString(int constant) throws XMLStreamException { switch(constant) { case ATTRIBUTE: return "ATTRIBUTE"; case CDATA: return "CDATA"; case CHARACTERS: return "CHARACTERS"; case COMMENT: return "COMMENT"; case DTD: return "DTD"; case END_DOCUMENT: return "END_DOCUMENT"; case END_ELEMENT: return "END_ELEMENT"; case ENTITY_DECLARATION: return "ENTITY_DECLARATION"; case ENTITY_REFERENCE: return "ENTITY_REFERENCE"; case NAMESPACE: return "NAMESPACE"; case NOTATION_DECLARATION: return "NOTATION_DECLARATION"; case PROCESSING_INSTRUCTION: return "PROCESSING_INSTRUCTION"; case SPACE: return "SPACE"; case START_DOCUMENT: return "START_DOCUMENT"; case START_ELEMENT: return "START_ELEMENT"; case -1: throw new XMLStreamException(L.l("Unexpected end of stream")); default: throw new RuntimeException(L.l("constantToString({0}) unknown", constant)); } } public static String printStreamState(XMLStreamReader in) throws XMLStreamException { StringBuilder sb = new StringBuilder(constantToString(in.getEventType())); if (in.getEventType() == in.START_ELEMENT || in.getEventType() == in.END_ELEMENT) { sb.append(": "); sb.append(in.getName()); } else if (in.getEventType() == in.CHARACTERS) { sb.append(": "); sb.append(in.getText()); } return sb.toString(); } /** * Converts a QName to a String using the context of a XMLStreamWriter. * Intended for writing QNames as attributes or text in a XMLStreamWriter * that's passed in. **/ public static String qnameToString(XMLStreamWriter out, QName qname) throws XMLStreamException { if (qname.getNamespaceURI() == null || "".equals(qname.getNamespaceURI())) return qname.getLocalPart(); NamespaceContext context = out.getNamespaceContext(); String prefix = context.getPrefix(qname.getNamespaceURI()); if (prefix == null) { if (qname.getPrefix() != null && ! "".equals(qname.getPrefix())) { out.writeNamespace(qname.getPrefix(), qname.getNamespaceURI()); return qname.getPrefix() + ':' + qname.getLocalPart(); } prefix = getNamespacePrefix(out, qname.getNamespaceURI()); // XXX this shouldn't be necessary out.writeNamespace(prefix, qname.getNamespaceURI()); } return prefix + ':' + qname.getLocalPart(); } public static void writeStartElement(XMLStreamWriter out, QName name) throws XMLStreamException { if (name == null) return; if (name.getPrefix() != null && ! "".equals(name.getPrefix())) out.writeStartElement(name.getPrefix(), name.getLocalPart(), name.getNamespaceURI()); else if (name.getNamespaceURI() != null && ! "".equals(name.getNamespaceURI())) out.writeStartElement(name.getNamespaceURI(), name.getLocalPart()); else out.writeStartElement(name.getLocalPart()); } public static void writeEndElement(XMLStreamWriter out, QName name) throws XMLStreamException { if (name == null) return; out.writeEndElement(); } public static void writeAttribute(XMLStreamWriter out, QName name, String value) throws XMLStreamException { if (name.getNamespaceURI() == null || "".equals(name.getNamespaceURI())) out.writeAttribute(name.getLocalPart(), value); else if (name.getPrefix() == null || "".equals(name.getPrefix())) out.writeAttribute(name.getNamespaceURI(), name.getLocalPart(), value); else out.writeAttribute(name.getPrefix(), name.getNamespaceURI(), name.getLocalPart(), value); } }