1:
37:
38: package ;
39:
40: import ;
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46:
47: import ;
48: import ;
49: import ;
50: import ;
51:
52: import ;
53:
54:
59: public class XMLStreamWriterImpl
60: implements XMLStreamWriter
61: {
62:
63:
66: protected final Writer writer;
67:
68:
72: protected final String encoding;
73:
74:
80: protected final boolean prefixDefaulting;
81:
82:
86: protected NamespaceContext namespaceContext;
87:
88:
92: private LinkedList elements;
93:
94:
97: private boolean inStartElement;
98:
99:
102: private boolean emptyElement;
103:
104: private NamespaceSupport namespaces;
105: private int count = 0;
106:
107:
113: protected XMLStreamWriterImpl(Writer writer, String encoding,
114: boolean prefixDefaulting)
115: {
116: this.writer = writer;
117: this.encoding = encoding;
118: this.prefixDefaulting = prefixDefaulting;
119: elements = new LinkedList();
120: namespaces = new NamespaceSupport();
121: }
122:
123:
127: private void endStartElement()
128: throws IOException
129: {
130: if (!inStartElement)
131: return;
132: if (emptyElement)
133: {
134: writer.write('/');
135: elements.removeLast();
136: namespaces.popContext();
137: emptyElement = false;
138: }
139: writer.write('>');
140: inStartElement = false;
141: }
142:
143: public void writeStartElement(String localName)
144: throws XMLStreamException
145: {
146: try
147: {
148: endStartElement();
149: namespaces.pushContext();
150:
151: writer.write('<');
152: writer.write(localName);
153:
154: elements.addLast(new String[] { null, localName });
155: inStartElement = true;
156: }
157: catch (IOException e)
158: {
159: XMLStreamException e2 = new XMLStreamException(e);
160: e2.initCause(e);
161: throw e2;
162: }
163: }
164:
165: public void writeStartElement(String namespaceURI, String localName)
166: throws XMLStreamException
167: {
168: try
169: {
170: endStartElement();
171: namespaces.pushContext();
172:
173: String prefix = getPrefix(namespaceURI);
174: boolean isDeclared = (prefix != null);
175: if (!isDeclared)
176: {
177: if (prefixDefaulting)
178: prefix = createPrefix(namespaceURI);
179: else
180: throw new XMLStreamException("namespace " + namespaceURI +
181: " has not been declared");
182: }
183: writer.write('<');
184: if (!"".equals(prefix))
185: {
186: writer.write(prefix);
187: writer.write(':');
188: }
189: writer.write(localName);
190: inStartElement = true;
191: if (!isDeclared)
192: {
193: writeNamespace(prefix, namespaceURI);
194: }
195:
196: elements.addLast(new String[] { prefix, localName });
197: }
198: catch (IOException e)
199: {
200: XMLStreamException e2 = new XMLStreamException(e);
201: e2.initCause(e);
202: throw e2;
203: }
204: }
205:
206:
212: protected String createPrefix(String namespaceURI)
213: {
214: Set prefixes = new HashSet();
215: for (Enumeration e = namespaces.getPrefixes(); e.hasMoreElements(); )
216: prefixes.add(e.nextElement());
217: String ret;
218: do
219: {
220: ret = "ns" + (count++);
221: }
222: while (prefixes.contains(ret));
223: return ret;
224: }
225:
226: public void writeStartElement(String prefix, String localName,
227: String namespaceURI)
228: throws XMLStreamException
229: {
230: try
231: {
232: endStartElement();
233: namespaces.pushContext();
234:
235: String currentPrefix = getPrefix(namespaceURI);
236: boolean isCurrent = prefix.equals(currentPrefix);
237: writer.write('<');
238: if (!"".equals(prefix))
239: {
240: writer.write(prefix);
241: writer.write(':');
242: }
243: writer.write(localName);
244: if (prefixDefaulting && !isCurrent)
245: {
246: writeNamespace(prefix, namespaceURI);
247: }
248:
249: elements.addLast(new String[] { prefix, localName });
250: inStartElement = true;
251: }
252: catch (IOException e)
253: {
254: XMLStreamException e2 = new XMLStreamException(e);
255: e2.initCause(e);
256: throw e2;
257: }
258: }
259:
260: public void writeEmptyElement(String namespaceURI, String localName)
261: throws XMLStreamException
262: {
263: writeStartElement(namespaceURI, localName);
264: emptyElement = true;
265: }
266:
267: public void writeEmptyElement(String prefix, String localName,
268: String namespaceURI)
269: throws XMLStreamException
270: {
271: writeStartElement(prefix, localName, namespaceURI);
272: emptyElement = true;
273: }
274:
275: public void writeEmptyElement(String localName)
276: throws XMLStreamException
277: {
278: writeStartElement(localName);
279: emptyElement = true;
280: }
281:
282: public void writeEndElement()
283: throws XMLStreamException
284: {
285: try
286: {
287: endStartElement();
288: String[] element = (String[]) elements.removeLast();
289: namespaces.popContext();
290:
291: writer.write('<');
292: writer.write('/');
293: if (element[0] != null && !"".equals(element[0]))
294: {
295: writer.write(element[0]);
296: writer.write(':');
297: }
298: writer.write(element[1]);
299: writer.write('>');
300: }
301: catch (IOException e)
302: {
303: XMLStreamException e2 = new XMLStreamException(e);
304: e2.initCause(e);
305: throw e2;
306: }
307: }
308:
309: public void writeEndDocument()
310: throws XMLStreamException
311: {
312: while (!elements.isEmpty())
313: writeEndElement();
314: }
315:
316: public void close()
317: throws XMLStreamException
318: {
319: flush();
320: }
321:
322: public void flush()
323: throws XMLStreamException
324: {
325: try
326: {
327: writer.flush();
328: }
329: catch (IOException e)
330: {
331: XMLStreamException e2 = new XMLStreamException(e);
332: e2.initCause(e);
333: throw e2;
334: }
335: }
336:
337: public void writeAttribute(String localName, String value)
338: throws XMLStreamException
339: {
340: if (!inStartElement)
341: throw new IllegalStateException();
342: try
343: {
344: writer.write(' ');
345: writer.write(localName);
346: writer.write('=');
347: writer.write('"');
348: writeEncoded(value, true);
349: writer.write('"');
350: }
351: catch (IOException e)
352: {
353: XMLStreamException e2 = new XMLStreamException(e);
354: e2.initCause(e);
355: throw e2;
356: }
357: }
358:
359: public void writeAttribute(String prefix, String namespaceURI,
360: String localName, String value)
361: throws XMLStreamException
362: {
363: if (!inStartElement)
364: throw new IllegalStateException();
365: try
366: {
367: String currentPrefix = getPrefix(namespaceURI);
368: if (currentPrefix == null)
369: {
370: if (prefixDefaulting)
371: writeNamespace(prefix, namespaceURI);
372: else
373: throw new XMLStreamException("namespace " + namespaceURI +
374: " is not bound");
375: }
376: else if (!currentPrefix.equals(prefix))
377: throw new XMLStreamException("namespace " + namespaceURI +
378: " is bound to prefix " +
379: currentPrefix);
380: writer.write(' ');
381: if (!"".equals(prefix))
382: {
383: writer.write(prefix);
384: writer.write(':');
385: }
386: writer.write(localName);
387: writer.write('=');
388: writer.write('"');
389: writeEncoded(value, true);
390: writer.write('"');
391: }
392: catch (IOException e)
393: {
394: XMLStreamException e2 = new XMLStreamException(e);
395: e2.initCause(e);
396: throw e2;
397: }
398: }
399:
400: public void writeAttribute(String namespaceURI, String localName,
401: String value)
402: throws XMLStreamException
403: {
404: if (!inStartElement)
405: throw new IllegalStateException();
406: try
407: {
408: String prefix = getPrefix(namespaceURI);
409: if (prefix == null)
410: {
411: if (prefixDefaulting)
412: {
413: prefix = XMLConstants.DEFAULT_NS_PREFIX;
414: writeNamespace(prefix, namespaceURI);
415: }
416: else
417: throw new XMLStreamException("namespace " + namespaceURI +
418: " is not bound");
419: }
420: writer.write(' ');
421: if (!"".equals(prefix))
422: {
423: writer.write(prefix);
424: writer.write(':');
425: }
426: writer.write(localName);
427: writer.write('=');
428: writer.write('"');
429: writeEncoded(value, true);
430: writer.write('"');
431: }
432: catch (IOException e)
433: {
434: XMLStreamException e2 = new XMLStreamException(e);
435: e2.initCause(e);
436: throw e2;
437: }
438: }
439:
440: public void writeNamespace(String prefix, String namespaceURI)
441: throws XMLStreamException
442: {
443: if (!inStartElement)
444: throw new IllegalStateException();
445: try
446: {
447: if (prefix == null)
448: prefix = XMLConstants.DEFAULT_NS_PREFIX;
449:
450: setPrefix(prefix, namespaceURI);
451:
452: writer.write(' ');
453: writer.write("xmlns");
454: if (!XMLConstants.DEFAULT_NS_PREFIX.equals(prefix))
455: {
456: writer.write(':');
457: writer.write(prefix);
458: }
459: writer.write('=');
460: writer.write('"');
461: writer.write(namespaceURI);
462: writer.write('"');
463: }
464: catch (IOException e)
465: {
466: XMLStreamException e2 = new XMLStreamException(e);
467: e2.initCause(e);
468: throw e2;
469: }
470: }
471:
472: public void writeDefaultNamespace(String namespaceURI)
473: throws XMLStreamException
474: {
475: writeNamespace(XMLConstants.DEFAULT_NS_PREFIX, namespaceURI);
476: }
477:
478: public void writeComment(String data)
479: throws XMLStreamException
480: {
481: try
482: {
483: endStartElement();
484:
485: if (data != null && data.indexOf("--") != -1)
486: throw new IllegalArgumentException(data);
487:
488: writer.write("<!--");
489: if (data != null)
490: writer.write(data);
491: writer.write("-->");
492: }
493: catch (IOException e)
494: {
495: XMLStreamException e2 = new XMLStreamException(e);
496: e2.initCause(e);
497: throw e2;
498: }
499: }
500:
501: public void writeProcessingInstruction(String target)
502: throws XMLStreamException
503: {
504: writeProcessingInstruction(target, null);
505: }
506:
507: public void writeProcessingInstruction(String target, String data)
508: throws XMLStreamException
509: {
510: try
511: {
512: endStartElement();
513:
514: writer.write('<');
515: writer.write('?');
516: writer.write(target);
517: if (data != null)
518: {
519: writer.write(' ');
520: writer.write(data);
521: }
522: writer.write('?');
523: writer.write('>');
524: }
525: catch (IOException e)
526: {
527: XMLStreamException e2 = new XMLStreamException(e);
528: e2.initCause(e);
529: throw e2;
530: }
531: }
532:
533: public void writeCData(String data)
534: throws XMLStreamException
535: {
536: try
537: {
538: endStartElement();
539:
540: if (data.indexOf("]]") != -1)
541: throw new IllegalArgumentException(data);
542:
543: writer.write("<![CDATA[");
544: writer.write(data);
545: writer.write("]]>");
546: }
547: catch (IOException e)
548: {
549: XMLStreamException e2 = new XMLStreamException(e);
550: e2.initCause(e);
551: throw e2;
552: }
553: }
554:
555: public void writeDTD(String dtd)
556: throws XMLStreamException
557: {
558: try
559: {
560: writer.write("<!DOCTYPE ");
561: writer.write(dtd);
562: writer.write('>');
563: }
564: catch (IOException e)
565: {
566: XMLStreamException e2 = new XMLStreamException(e);
567: e2.initCause(e);
568: throw e2;
569: }
570: }
571:
572: public void writeEntityRef(String name)
573: throws XMLStreamException
574: {
575: try
576: {
577: endStartElement();
578:
579: writer.write('&');
580: writer.write(name);
581: writer.write(';');
582: }
583: catch (IOException e)
584: {
585: XMLStreamException e2 = new XMLStreamException(e);
586: e2.initCause(e);
587: throw e2;
588: }
589: }
590:
591: public void writeStartDocument()
592: throws XMLStreamException
593: {
594: writeStartDocument(null, null);
595: }
596:
597: public void writeStartDocument(String version)
598: throws XMLStreamException
599: {
600: writeStartDocument(null, version);
601: }
602:
603: public void writeStartDocument(String encoding, String version)
604: throws XMLStreamException
605: {
606: if (version == null)
607: version = "1.0";
608: encoding = this.encoding;
609: if (encoding == null)
610: encoding = "UTF-8";
611: if (!"1.0".equals(version) && !"1.1".equals(version))
612: throw new IllegalArgumentException(version);
613: try
614: {
615: writer.write("<?xml version=\"");
616: writer.write(version);
617: writer.write("\" encoding=\"");
618: writer.write(encoding);
619: writer.write("\"?>");
620: writer.write(System.getProperty("line.separator"));
621: }
622: catch (IOException e)
623: {
624: XMLStreamException e2 = new XMLStreamException(e);
625: e2.initCause(e);
626: throw e2;
627: }
628: }
629:
630: public void writeCharacters(String text)
631: throws XMLStreamException
632: {
633: try
634: {
635: endStartElement();
636:
637: if (text != null)
638: writeEncoded(text, false);
639: }
640: catch (IOException e)
641: {
642: XMLStreamException e2 = new XMLStreamException(e);
643: e2.initCause(e);
644: throw e2;
645: }
646: }
647:
648: public void writeCharacters(char[] text, int start, int len)
649: throws XMLStreamException
650: {
651: try
652: {
653: endStartElement();
654:
655: int end = start + len;
656: len = 0;
657: for (int i = start; i < end; i++)
658: {
659: char c = text[i];
660: if (c == '<' || c == '>' || c == '&')
661: {
662: writer.write(text, start, len);
663: if (c == '<')
664: writer.write("<");
665: else if (c == '>')
666: writer.write(">");
667: else
668: writer.write("&");
669: start = i + 1;
670: len = 0;
671: }
672: else
673: len++;
674: }
675: if (len > 0)
676: writer.write(text, start, len);
677: }
678: catch (IOException e)
679: {
680: XMLStreamException e2 = new XMLStreamException(e);
681: e2.initCause(e);
682: throw e2;
683: }
684: }
685:
686: public String getPrefix(String uri)
687: throws XMLStreamException
688: {
689: String prefix = namespaces.getPrefix(uri);
690: if (prefix == null && namespaceContext != null)
691: prefix = namespaceContext.getPrefix(uri);
692: return prefix;
693: }
694:
695: public void setPrefix(String prefix, String uri)
696: throws XMLStreamException
697: {
698: if (!namespaces.declarePrefix(prefix, uri))
699: throw new XMLStreamException("illegal prefix " + prefix);
700: }
701:
702: public void setDefaultNamespace(String uri)
703: throws XMLStreamException
704: {
705: if (!namespaces.declarePrefix(XMLConstants.DEFAULT_NS_PREFIX, uri))
706: throw new XMLStreamException("illegal default namespace prefix");
707: }
708:
709: public void setNamespaceContext(NamespaceContext context)
710: throws XMLStreamException
711: {
712: namespaceContext = context;
713: }
714:
715: public NamespaceContext getNamespaceContext()
716: {
717: return namespaceContext;
718: }
719:
720: public Object getProperty(String name)
721: throws IllegalArgumentException
722: {
723: throw new IllegalArgumentException(name);
724: }
725:
726:
732: private void writeEncoded(String text, boolean inAttr)
733: throws IOException
734: {
735: char[] chars = text.toCharArray();
736: int start = 0;
737: int end = chars.length;
738: int len = 0;
739: for (int i = start; i < end; i++)
740: {
741: char c = chars[i];
742: if (c == '<' || c == '>' || c == '&')
743: {
744: writer.write(chars, start, len);
745: if (c == '<')
746: writer.write("<");
747: else if (c == '>')
748: writer.write(">");
749: else
750: writer.write("&");
751: start = i + 1;
752: len = 0;
753: }
754: else if (inAttr && (c == '"' || c == '\''))
755: {
756: writer.write(chars, start, len);
757: if (c == '"')
758: writer.write(""");
759: else
760: writer.write("'");
761: start = i + 1;
762: len = 0;
763: }
764: else
765: len++;
766: }
767: if (len > 0)
768: writer.write(chars, start, len);
769: }
770:
771: }