001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Emil Ong
028: */
029:
030: package com.caucho.xml.stream;
031:
032: import static javax.xml.XMLConstants.*;
033: import javax.xml.namespace.NamespaceContext;
034: import javax.xml.namespace.QName;
035: import javax.xml.stream.XMLOutputFactory;
036: import static javax.xml.stream.XMLStreamConstants.*;
037: import javax.xml.stream.XMLStreamException;
038: import javax.xml.stream.XMLStreamReader;
039: import javax.xml.stream.XMLStreamWriter;
040:
041: import java.io.IOException;
042:
043: import java.util.Iterator;
044:
045: import com.caucho.util.L10N;
046:
047: /**
048: * Utility class to do namespace repairs on XMLStreamWriters that don't have
049: * repair enabled. Used by JAXB.
050: **/
051: public class StaxUtil {
052: public static final L10N L = new L10N(StaxUtil.class);
053:
054: public static QName resolveStringToQName(String string,
055: XMLStreamReader in) throws XMLStreamException {
056: return resolveStringToQName(string, in.getNamespaceContext());
057: }
058:
059: public static QName resolveStringToQName(String string,
060: NamespaceContext context) throws XMLStreamException {
061: int colon = string.indexOf(':');
062:
063: if (colon < 0)
064: return new QName(string);
065:
066: if (colon + 1 >= string.length())
067: throw new XMLStreamException(L.l(
068: "Invalid qualified name: {0}", string));
069:
070: String prefix = string.substring(0, colon);
071: String localName = string.substring(colon + 1);
072: String namespace = context.getNamespaceURI(prefix);
073:
074: if (NULL_NS_URI.equals(namespace))
075: throw new XMLStreamException(L.l(
076: "No namespace for qualifed name: {0}", string));
077:
078: return new QName(namespace, localName, prefix);
079: }
080:
081: /**
082: * Ensures that a given namespace exists within the namespace context
083: * given.
084: **/
085: public static void repairNamespace(XMLStreamWriter out,
086: String namespace) throws XMLStreamException {
087: try {
088: Object repairing = out
089: .getProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES);
090:
091: if (Boolean.TRUE.equals(repairing))
092: return;
093: } catch (IllegalArgumentException e) {
094: } catch (NullPointerException e) {
095: }
096:
097: getNamespacePrefix(out, namespace);
098: }
099:
100: /**
101: * Ensures that a given namespace exists within the namespace context
102: * given and returns the prefix.
103: **/
104: public static String getNamespacePrefix(XMLStreamWriter out,
105: String namespace) throws XMLStreamException {
106: NamespaceContext context = out.getNamespaceContext();
107: String prefix = context.getPrefix(namespace);
108:
109: if (prefix != null)
110: return prefix;
111:
112: if (context instanceof NamespaceWriterContext) {
113: NamespaceWriterContext writerContext = (NamespaceWriterContext) context;
114:
115: boolean repair = writerContext.getRepair();
116:
117: writerContext.setRepair(true);
118: prefix = writerContext.declare(namespace);
119: writerContext.setRepair(repair);
120:
121: return prefix;
122: } else {
123: // not one of ours...
124: // we have to search for a unique prefix...
125: int i = 0;
126: String unique = "ns" + i;
127:
128: while (true) {
129: boolean found = false;
130: Iterator iterator = context.getPrefixes(namespace);
131:
132: while (iterator.hasNext()) {
133: prefix = iterator.next().toString();
134:
135: if (prefix.equals(unique)) {
136: i++;
137: unique = "ns" + i;
138: found = true;
139: break;
140: }
141: }
142:
143: if (!found)
144: break;
145: }
146:
147: out.writeNamespace(unique, namespace);
148:
149: return unique;
150: }
151: }
152:
153: /**
154: * Ensures that a given prefix->namespace mapping exists within the
155: * namespace context given.
156: **/
157: public static void repairNamespace(XMLStreamWriter out,
158: String prefix, String namespace) throws XMLStreamException {
159: try {
160: Object repairing = out
161: .getProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES);
162:
163: if (Boolean.TRUE.equals(repairing))
164: return;
165: } catch (IllegalArgumentException e) {
166: } catch (NullPointerException e) {
167: }
168:
169: NamespaceContext context = out.getNamespaceContext();
170:
171: String oldPrefix = context.getPrefix(namespace);
172:
173: if (!prefix.equals(oldPrefix))
174: out.writeNamespace(prefix, namespace);
175: }
176:
177: public static XMLStreamWriter toRepairingXMLStreamWriter(
178: XMLStreamWriter out) {
179: try {
180: Object repairing = out
181: .getProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES);
182:
183: if (Boolean.TRUE.equals(repairing))
184: return out;
185: } catch (IllegalArgumentException e) {
186: } catch (NullPointerException e) {
187: }
188:
189: if (out instanceof XMLStreamWriterImpl) {
190: ((XMLStreamWriterImpl) out).setRepair(true);
191:
192: return out;
193: } else {
194: return new XMLStreamWriterRepairingWrapper(out);
195: }
196: }
197:
198: /**
199: * Copys all the events from the input to the output, without going past
200: * an unmatch end element.
201: *
202: * E.g.: if the input is at the start of <y>, it will only read just past </y>
203: *
204: * <x>
205: * <y>
206: * <z/>
207: * </y>
208: * </x>
209: *
210: **/
211: public static void copyReaderToWriter(XMLStreamReader in,
212: XMLStreamWriter out) throws XMLStreamException {
213: int depth = 0;
214:
215: do {
216: switch (in.getEventType()) {
217: case ATTRIBUTE:
218: break;
219:
220: case CDATA:
221: out.writeCData(in.getText());
222: break;
223:
224: case CHARACTERS:
225: out.writeCharacters(in.getText());
226: break;
227:
228: case COMMENT:
229: out.writeComment(in.getText());
230: break;
231:
232: case DTD:
233: out.writeDTD(in.getText());
234: break;
235:
236: case END_DOCUMENT:
237: out.writeEndDocument();
238: break;
239:
240: case END_ELEMENT:
241: depth--;
242:
243: if (depth < 0) {
244: out.flush();
245:
246: return;
247: }
248:
249: out.writeEndElement();
250: break;
251:
252: case ENTITY_REFERENCE:
253: out.writeEntityRef(in.getText());
254: break;
255:
256: case NAMESPACE:
257: break;
258:
259: case PROCESSING_INSTRUCTION:
260: out.writeProcessingInstruction(in.getPITarget(), in
261: .getPIData());
262: break;
263:
264: case SPACE:
265: out.writeCharacters(in.getText());
266: break;
267:
268: case START_DOCUMENT:
269: out.writeStartDocument(in.getEncoding(), in
270: .getVersion());
271: break;
272:
273: case START_ELEMENT:
274: QName qname = in.getName();
275:
276: if (qname.getNamespaceURI() == null
277: || "".equals(qname.getNamespaceURI()))
278: out.writeStartElement(qname.getLocalPart());
279: else if (qname.getPrefix() == null
280: || "".equals(qname.getPrefix()))
281: out.writeStartElement(qname.getNamespaceURI(),
282: qname.getLocalPart());
283: else
284: out.writeStartElement(qname.getPrefix(), qname
285: .getLocalPart(), qname.getNamespaceURI());
286:
287: for (int i = 0; i < in.getAttributeCount(); i++) {
288: qname = in.getAttributeName(i);
289: String value = in.getAttributeValue(i);
290:
291: if (qname.getNamespaceURI() == null
292: || "".equals(qname.getNamespaceURI()))
293: out.writeAttribute(qname.getLocalPart(), value);
294: else if (qname.getPrefix() == null
295: || "".equals(qname.getPrefix()))
296: out.writeAttribute(qname.getNamespaceURI(),
297: qname.getLocalPart(), value);
298: else
299: out.writeAttribute(qname.getPrefix(), qname
300: .getNamespaceURI(), qname
301: .getLocalPart(), value);
302: }
303:
304: for (int i = 0; i < in.getNamespaceCount(); i++)
305: out.writeNamespace(in.getNamespacePrefix(i), in
306: .getNamespaceURI(i));
307:
308: depth++;
309: break;
310: }
311:
312: if (in.hasNext())
313: in.next();
314: else
315: break;
316: } while (depth >= 0);
317:
318: out.flush();
319: }
320:
321: public static String constantToString(int constant)
322: throws XMLStreamException {
323: switch (constant) {
324: case ATTRIBUTE:
325: return "ATTRIBUTE";
326: case CDATA:
327: return "CDATA";
328: case CHARACTERS:
329: return "CHARACTERS";
330: case COMMENT:
331: return "COMMENT";
332: case DTD:
333: return "DTD";
334: case END_DOCUMENT:
335: return "END_DOCUMENT";
336: case END_ELEMENT:
337: return "END_ELEMENT";
338: case ENTITY_DECLARATION:
339: return "ENTITY_DECLARATION";
340: case ENTITY_REFERENCE:
341: return "ENTITY_REFERENCE";
342: case NAMESPACE:
343: return "NAMESPACE";
344: case NOTATION_DECLARATION:
345: return "NOTATION_DECLARATION";
346: case PROCESSING_INSTRUCTION:
347: return "PROCESSING_INSTRUCTION";
348: case SPACE:
349: return "SPACE";
350: case START_DOCUMENT:
351: return "START_DOCUMENT";
352: case START_ELEMENT:
353: return "START_ELEMENT";
354: case -1:
355: throw new XMLStreamException(L
356: .l("Unexpected end of stream"));
357: default:
358: throw new RuntimeException(L.l(
359: "constantToString({0}) unknown", constant));
360: }
361: }
362:
363: public static String printStreamState(XMLStreamReader in)
364: throws XMLStreamException {
365: StringBuilder sb = new StringBuilder(constantToString(in
366: .getEventType()));
367:
368: if (in.getEventType() == in.START_ELEMENT
369: || in.getEventType() == in.END_ELEMENT) {
370: sb.append(": ");
371: sb.append(in.getName());
372: } else if (in.getEventType() == in.CHARACTERS) {
373: sb.append(": ");
374: sb.append(in.getText());
375: }
376:
377: return sb.toString();
378: }
379:
380: /**
381: * Converts a QName to a String using the context of a XMLStreamWriter.
382: * Intended for writing QNames as attributes or text in a XMLStreamWriter
383: * that's passed in.
384: **/
385: public static String qnameToString(XMLStreamWriter out, QName qname)
386: throws XMLStreamException {
387: if (qname.getNamespaceURI() == null
388: || "".equals(qname.getNamespaceURI()))
389: return qname.getLocalPart();
390:
391: NamespaceContext context = out.getNamespaceContext();
392: String prefix = context.getPrefix(qname.getNamespaceURI());
393:
394: if (prefix == null) {
395: if (qname.getPrefix() != null
396: && !"".equals(qname.getPrefix())) {
397: out.writeNamespace(qname.getPrefix(), qname
398: .getNamespaceURI());
399:
400: return qname.getPrefix() + ':' + qname.getLocalPart();
401: }
402:
403: prefix = getNamespacePrefix(out, qname.getNamespaceURI());
404:
405: // XXX this shouldn't be necessary
406: out.writeNamespace(prefix, qname.getNamespaceURI());
407: }
408:
409: return prefix + ':' + qname.getLocalPart();
410: }
411:
412: public static void writeStartElement(XMLStreamWriter out, QName name)
413: throws XMLStreamException {
414: if (name == null)
415: return;
416:
417: if (name.getPrefix() != null && !"".equals(name.getPrefix()))
418: out.writeStartElement(name.getPrefix(),
419: name.getLocalPart(), name.getNamespaceURI());
420: else if (name.getNamespaceURI() != null
421: && !"".equals(name.getNamespaceURI()))
422: out.writeStartElement(name.getNamespaceURI(), name
423: .getLocalPart());
424: else
425: out.writeStartElement(name.getLocalPart());
426: }
427:
428: public static void writeEndElement(XMLStreamWriter out, QName name)
429: throws XMLStreamException {
430: if (name == null)
431: return;
432:
433: out.writeEndElement();
434: }
435:
436: public static void writeAttribute(XMLStreamWriter out, QName name,
437: String value) throws XMLStreamException {
438: if (name.getNamespaceURI() == null
439: || "".equals(name.getNamespaceURI()))
440: out.writeAttribute(name.getLocalPart(), value);
441:
442: else if (name.getPrefix() == null
443: || "".equals(name.getPrefix()))
444: out.writeAttribute(name.getNamespaceURI(), name
445: .getLocalPart(), value);
446:
447: else
448: out.writeAttribute(name.getPrefix(),
449: name.getNamespaceURI(), name.getLocalPart(), value);
450: }
451: }
|