XMLStreamWriterImpl.java 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017
  1. /* XMLStreamWriterImpl.java --
  2. Copyright (C) 2005 Free Software Foundation, Inc.
  3. This file is part of GNU Classpath.
  4. GNU Classpath is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. GNU Classpath is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Classpath; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  15. 02110-1301 USA.
  16. Linking this library statically or dynamically with other modules is
  17. making a combined work based on this library. Thus, the terms and
  18. conditions of the GNU General Public License cover the whole
  19. combination.
  20. As a special exception, the copyright holders of this library give you
  21. permission to link this library with independent modules to produce an
  22. executable, regardless of the license terms of these independent
  23. modules, and to copy and distribute the resulting executable under
  24. terms of your choice, provided that you also meet, for each linked
  25. independent module, the terms and conditions of the license of that
  26. module. An independent module is a module which is not derived from
  27. or based on this library. If you modify this library, you may extend
  28. this exception to your version of the library, but you are not
  29. obligated to do so. If you do not wish to do so, delete this
  30. exception statement from your version. */
  31. package gnu.xml.stream;
  32. import java.io.IOException;
  33. import java.io.Writer;
  34. import java.util.Enumeration;
  35. import java.util.HashSet;
  36. import java.util.LinkedList;
  37. import java.util.Set;
  38. import javax.xml.XMLConstants;
  39. import javax.xml.namespace.NamespaceContext;
  40. import javax.xml.stream.XMLStreamException;
  41. import javax.xml.stream.XMLStreamWriter;
  42. import org.xml.sax.helpers.NamespaceSupport;
  43. /**
  44. * Simple XML stream writer.
  45. *
  46. * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
  47. */
  48. public class XMLStreamWriterImpl
  49. implements XMLStreamWriter
  50. {
  51. /**
  52. * The underlying character stream to write to.
  53. */
  54. protected final Writer writer;
  55. /**
  56. * The encoding being used.
  57. * Note that this must match the encoding of the character stream.
  58. */
  59. protected final String encoding;
  60. /**
  61. * Whether prefix defaulting is being used.
  62. * If true and a prefix has not been defined for a namespace specified on
  63. * an element or an attribute, a new prefix and namespace declaration will
  64. * be created.
  65. */
  66. protected final boolean prefixDefaulting;
  67. /**
  68. * The namespace context used to determine the namespace-prefix mappings
  69. * in scope.
  70. */
  71. protected NamespaceContext namespaceContext;
  72. /**
  73. * The stack of elements in scope.
  74. * Used to close the remaining elements.
  75. */
  76. private LinkedList elements;
  77. /**
  78. * Whether a start element has been opened but not yet closed.
  79. */
  80. private boolean inStartElement;
  81. /**
  82. * Whether we are in an empty element.
  83. */
  84. private boolean emptyElement;
  85. private NamespaceSupport namespaces;
  86. private int count = 0;
  87. private boolean xml11;
  88. private boolean hasXML11RestrictedChars;
  89. /**
  90. * Constructor.
  91. * @see #writer
  92. * @see #encoding
  93. * @see #prefixDefaulting
  94. */
  95. protected XMLStreamWriterImpl(Writer writer, String encoding,
  96. boolean prefixDefaulting)
  97. {
  98. this.writer = writer;
  99. this.encoding = encoding;
  100. this.prefixDefaulting = prefixDefaulting;
  101. elements = new LinkedList();
  102. namespaces = new NamespaceSupport();
  103. }
  104. /**
  105. * Write the end of a start-element event.
  106. * This will close the element if it was defined to be an empty element.
  107. */
  108. private void endStartElement()
  109. throws IOException
  110. {
  111. if (!inStartElement)
  112. return;
  113. if (emptyElement)
  114. {
  115. writer.write('/');
  116. elements.removeLast();
  117. namespaces.popContext();
  118. emptyElement = false;
  119. }
  120. writer.write('>');
  121. inStartElement = false;
  122. }
  123. public void writeStartElement(String localName)
  124. throws XMLStreamException
  125. {
  126. try
  127. {
  128. if (!isName(localName))
  129. throw new IllegalArgumentException("illegal Name: " + localName);
  130. endStartElement();
  131. namespaces.pushContext();
  132. writer.write('<');
  133. writer.write(localName);
  134. elements.addLast(new String[] { null, localName });
  135. inStartElement = true;
  136. }
  137. catch (IOException e)
  138. {
  139. XMLStreamException e2 = new XMLStreamException(e);
  140. e2.initCause(e);
  141. throw e2;
  142. }
  143. }
  144. public void writeStartElement(String namespaceURI, String localName)
  145. throws XMLStreamException
  146. {
  147. try
  148. {
  149. if (namespaceURI != null && !isURI(namespaceURI))
  150. throw new IllegalArgumentException("illegal URI: " + namespaceURI);
  151. if (!isName(localName))
  152. throw new IllegalArgumentException("illegal Name: " + localName);
  153. endStartElement();
  154. namespaces.pushContext();
  155. String prefix = getPrefix(namespaceURI);
  156. boolean isDeclared = (prefix != null);
  157. if (!isDeclared)
  158. {
  159. if (prefixDefaulting)
  160. prefix = createPrefix(namespaceURI);
  161. else
  162. throw new XMLStreamException("namespace " + namespaceURI +
  163. " has not been declared");
  164. }
  165. writer.write('<');
  166. if (!"".equals(prefix))
  167. {
  168. writer.write(prefix);
  169. writer.write(':');
  170. }
  171. writer.write(localName);
  172. inStartElement = true;
  173. if (!isDeclared)
  174. {
  175. writeNamespaceImpl(prefix, namespaceURI);
  176. }
  177. elements.addLast(new String[] { prefix, localName });
  178. }
  179. catch (IOException e)
  180. {
  181. XMLStreamException e2 = new XMLStreamException(e);
  182. e2.initCause(e);
  183. throw e2;
  184. }
  185. }
  186. /**
  187. * Creates a new unique prefix in the document.
  188. * Subclasses may override this method to provide a suitably unique prefix
  189. * for the given namespace.
  190. * @param namespaceURI the namespace URI
  191. */
  192. protected String createPrefix(String namespaceURI)
  193. {
  194. Set prefixes = new HashSet();
  195. for (Enumeration e = namespaces.getPrefixes(); e.hasMoreElements(); )
  196. prefixes.add(e.nextElement());
  197. String ret;
  198. do
  199. {
  200. ret = "ns" + (count++);
  201. }
  202. while (prefixes.contains(ret));
  203. return ret;
  204. }
  205. public void writeStartElement(String prefix, String localName,
  206. String namespaceURI)
  207. throws XMLStreamException
  208. {
  209. try
  210. {
  211. if (namespaceURI != null && !isURI(namespaceURI))
  212. throw new IllegalArgumentException("illegal URI: " + namespaceURI);
  213. if (prefix != null && !isPrefix(prefix))
  214. throw new IllegalArgumentException("illegal NCName: " + prefix);
  215. if (!isNCName(localName))
  216. throw new IllegalArgumentException("illegal NCName: " + localName);
  217. endStartElement();
  218. namespaces.pushContext();
  219. String currentPrefix = getPrefix(namespaceURI);
  220. boolean isCurrent = prefix.equals(currentPrefix);
  221. writer.write('<');
  222. if (!"".equals(prefix))
  223. {
  224. writer.write(prefix);
  225. writer.write(':');
  226. }
  227. writer.write(localName);
  228. if (prefixDefaulting && !isCurrent)
  229. {
  230. writeNamespaceImpl(prefix, namespaceURI);
  231. }
  232. elements.addLast(new String[] { prefix, localName });
  233. inStartElement = true;
  234. }
  235. catch (IOException e)
  236. {
  237. XMLStreamException e2 = new XMLStreamException(e);
  238. e2.initCause(e);
  239. throw e2;
  240. }
  241. }
  242. public void writeEmptyElement(String namespaceURI, String localName)
  243. throws XMLStreamException
  244. {
  245. writeStartElement(namespaceURI, localName);
  246. emptyElement = true;
  247. }
  248. public void writeEmptyElement(String prefix, String localName,
  249. String namespaceURI)
  250. throws XMLStreamException
  251. {
  252. writeStartElement(prefix, localName, namespaceURI);
  253. emptyElement = true;
  254. }
  255. public void writeEmptyElement(String localName)
  256. throws XMLStreamException
  257. {
  258. writeStartElement(localName);
  259. emptyElement = true;
  260. }
  261. public void writeEndElement()
  262. throws XMLStreamException
  263. {
  264. if (elements.isEmpty())
  265. throw new IllegalStateException("no matching start element");
  266. try
  267. {
  268. endStartElement();
  269. String[] element = (String[]) elements.removeLast();
  270. namespaces.popContext();
  271. writer.write('<');
  272. writer.write('/');
  273. if (element[0] != null && !"".equals(element[0]))
  274. {
  275. writer.write(element[0]);
  276. writer.write(':');
  277. }
  278. writer.write(element[1]);
  279. writer.write('>');
  280. }
  281. catch (IOException e)
  282. {
  283. XMLStreamException e2 = new XMLStreamException(e);
  284. e2.initCause(e);
  285. throw e2;
  286. }
  287. }
  288. public void writeEndDocument()
  289. throws XMLStreamException
  290. {
  291. while (!elements.isEmpty())
  292. writeEndElement();
  293. }
  294. public void close()
  295. throws XMLStreamException
  296. {
  297. flush();
  298. }
  299. public void flush()
  300. throws XMLStreamException
  301. {
  302. try
  303. {
  304. writer.flush();
  305. }
  306. catch (IOException e)
  307. {
  308. XMLStreamException e2 = new XMLStreamException(e);
  309. e2.initCause(e);
  310. throw e2;
  311. }
  312. }
  313. public void writeAttribute(String localName, String value)
  314. throws XMLStreamException
  315. {
  316. if (!inStartElement)
  317. throw new IllegalStateException();
  318. try
  319. {
  320. if (!isName(localName))
  321. throw new IllegalArgumentException("illegal Name: " + localName);
  322. if (!isChars(value))
  323. throw new IllegalArgumentException("illegal character: " + value);
  324. writer.write(' ');
  325. writer.write(localName);
  326. writer.write('=');
  327. writer.write('"');
  328. if (hasXML11RestrictedChars)
  329. writeEncodedWithRestrictedChars(value, true);
  330. else
  331. writeEncoded(value, true);
  332. writer.write('"');
  333. }
  334. catch (IOException e)
  335. {
  336. XMLStreamException e2 = new XMLStreamException(e);
  337. e2.initCause(e);
  338. throw e2;
  339. }
  340. }
  341. public void writeAttribute(String prefix, String namespaceURI,
  342. String localName, String value)
  343. throws XMLStreamException
  344. {
  345. if (!inStartElement)
  346. throw new IllegalStateException();
  347. try
  348. {
  349. if (namespaceURI != null && !isURI(namespaceURI))
  350. throw new IllegalArgumentException("illegal URI: " + namespaceURI);
  351. if (prefix != null && !isPrefix(prefix))
  352. throw new IllegalArgumentException("illegal NCName: " + prefix);
  353. if (!isNCName(localName))
  354. throw new IllegalArgumentException("illegal NCName: " + localName);
  355. if (!isChars(value))
  356. throw new IllegalArgumentException("illegal character: " + value);
  357. String currentPrefix = getPrefix(namespaceURI);
  358. if (currentPrefix == null)
  359. {
  360. if (prefixDefaulting)
  361. writeNamespaceImpl(prefix, namespaceURI);
  362. else
  363. throw new XMLStreamException("namespace " + namespaceURI +
  364. " is not bound");
  365. }
  366. else if (!currentPrefix.equals(prefix))
  367. throw new XMLStreamException("namespace " + namespaceURI +
  368. " is bound to prefix " +
  369. currentPrefix);
  370. writer.write(' ');
  371. if (!"".equals(prefix))
  372. {
  373. writer.write(prefix);
  374. writer.write(':');
  375. }
  376. writer.write(localName);
  377. writer.write('=');
  378. writer.write('"');
  379. if (hasXML11RestrictedChars)
  380. writeEncodedWithRestrictedChars(value, true);
  381. else
  382. writeEncoded(value, true);
  383. writer.write('"');
  384. }
  385. catch (IOException e)
  386. {
  387. XMLStreamException e2 = new XMLStreamException(e);
  388. e2.initCause(e);
  389. throw e2;
  390. }
  391. }
  392. public void writeAttribute(String namespaceURI, String localName,
  393. String value)
  394. throws XMLStreamException
  395. {
  396. if (!inStartElement)
  397. throw new IllegalStateException();
  398. try
  399. {
  400. if (namespaceURI != null && !isURI(namespaceURI))
  401. throw new IllegalArgumentException("illegal URI: " + namespaceURI);
  402. if (!isName(localName))
  403. throw new IllegalArgumentException("illegal Name: " + localName);
  404. if (!isChars(value))
  405. throw new IllegalArgumentException("illegal character: " + value);
  406. String prefix = getPrefix(namespaceURI);
  407. if (prefix == null)
  408. {
  409. if (prefixDefaulting)
  410. {
  411. prefix = XMLConstants.DEFAULT_NS_PREFIX;
  412. writeNamespaceImpl(prefix, namespaceURI);
  413. }
  414. else
  415. throw new XMLStreamException("namespace " + namespaceURI +
  416. " is not bound");
  417. }
  418. writer.write(' ');
  419. if (!"".equals(prefix))
  420. {
  421. writer.write(prefix);
  422. writer.write(':');
  423. }
  424. writer.write(localName);
  425. writer.write('=');
  426. writer.write('"');
  427. if (hasXML11RestrictedChars)
  428. writeEncodedWithRestrictedChars(value, true);
  429. else
  430. writeEncoded(value, true);
  431. writer.write('"');
  432. }
  433. catch (IOException e)
  434. {
  435. XMLStreamException e2 = new XMLStreamException(e);
  436. e2.initCause(e);
  437. throw e2;
  438. }
  439. }
  440. public void writeNamespace(String prefix, String namespaceURI)
  441. throws XMLStreamException
  442. {
  443. if (prefix == null || "".equals(prefix) || "xmlns".equals(prefix))
  444. {
  445. writeDefaultNamespace(namespaceURI);
  446. return;
  447. }
  448. if (!inStartElement)
  449. throw new IllegalStateException();
  450. try
  451. {
  452. if (!isURI(namespaceURI))
  453. throw new IllegalArgumentException("illegal URI: " + namespaceURI);
  454. if (!isPrefix(prefix))
  455. throw new IllegalArgumentException("illegal NCName: " + prefix);
  456. }
  457. catch (IOException e)
  458. {
  459. XMLStreamException e2 = new XMLStreamException(e);
  460. e2.initCause(e);
  461. throw e2;
  462. }
  463. writeNamespaceImpl(prefix, namespaceURI);
  464. }
  465. private void writeNamespaceImpl(String prefix, String namespaceURI)
  466. throws XMLStreamException
  467. {
  468. try
  469. {
  470. if (prefix == null)
  471. prefix = XMLConstants.DEFAULT_NS_PREFIX;
  472. setPrefix(prefix, namespaceURI);
  473. writer.write(' ');
  474. writer.write("xmlns");
  475. if (!XMLConstants.DEFAULT_NS_PREFIX.equals(prefix))
  476. {
  477. writer.write(':');
  478. writer.write(prefix);
  479. }
  480. writer.write('=');
  481. writer.write('"');
  482. writer.write(namespaceURI);
  483. writer.write('"');
  484. }
  485. catch (IOException e)
  486. {
  487. XMLStreamException e2 = new XMLStreamException(e);
  488. e2.initCause(e);
  489. throw e2;
  490. }
  491. }
  492. public void writeDefaultNamespace(String namespaceURI)
  493. throws XMLStreamException
  494. {
  495. if (!inStartElement)
  496. throw new IllegalStateException();
  497. if (!isURI(namespaceURI))
  498. throw new IllegalArgumentException("illegal URI: " + namespaceURI);
  499. writeNamespaceImpl(XMLConstants.DEFAULT_NS_PREFIX, namespaceURI);
  500. }
  501. public void writeComment(String data)
  502. throws XMLStreamException
  503. {
  504. if (data == null)
  505. return;
  506. try
  507. {
  508. if (!isChars(data))
  509. throw new IllegalArgumentException("illegal XML character: " + data);
  510. if (data.indexOf("--") != -1)
  511. throw new IllegalArgumentException("illegal comment: " + data);
  512. endStartElement();
  513. writer.write("<!--");
  514. if (hasXML11RestrictedChars)
  515. {
  516. int[] seq = UnicodeReader.toCodePointArray(data);
  517. for (int i = 0; i < seq.length; i++)
  518. {
  519. int c = seq[i];
  520. if (XMLParser.isXML11RestrictedChar(c))
  521. writer.write("&#x" + Integer.toHexString(c) + ";");
  522. else
  523. writer.write(Character.toChars(i));
  524. }
  525. }
  526. else
  527. writer.write(data);
  528. writer.write("-->");
  529. }
  530. catch (IOException e)
  531. {
  532. XMLStreamException e2 = new XMLStreamException(e);
  533. e2.initCause(e);
  534. throw e2;
  535. }
  536. }
  537. public void writeProcessingInstruction(String target)
  538. throws XMLStreamException
  539. {
  540. writeProcessingInstruction(target, null);
  541. }
  542. public void writeProcessingInstruction(String target, String data)
  543. throws XMLStreamException
  544. {
  545. try
  546. {
  547. if (!isName(target) || "xml".equalsIgnoreCase(target))
  548. throw new IllegalArgumentException("illegal PITarget: " + target);
  549. if (data != null && !isChars(data))
  550. throw new IllegalArgumentException("illegal XML character: " + data);
  551. endStartElement();
  552. writer.write('<');
  553. writer.write('?');
  554. writer.write(target);
  555. if (data != null)
  556. {
  557. writer.write(' ');
  558. if (hasXML11RestrictedChars)
  559. {
  560. int[] seq = UnicodeReader.toCodePointArray(data);
  561. for (int i = 0; i < seq.length; i++)
  562. {
  563. int c = seq[i];
  564. if (XMLParser.isXML11RestrictedChar(c))
  565. writer.write("&#x" + Integer.toHexString(c) + ";");
  566. else
  567. writer.write(Character.toChars(i));
  568. }
  569. }
  570. else
  571. writer.write(data);
  572. }
  573. writer.write('?');
  574. writer.write('>');
  575. }
  576. catch (IOException e)
  577. {
  578. XMLStreamException e2 = new XMLStreamException(e);
  579. e2.initCause(e);
  580. throw e2;
  581. }
  582. }
  583. public void writeCData(String data)
  584. throws XMLStreamException
  585. {
  586. try
  587. {
  588. if (!isChars(data) || hasXML11RestrictedChars)
  589. throw new IllegalArgumentException("illegal XML character: " + data);
  590. if (data.indexOf("]]") != -1)
  591. throw new IllegalArgumentException("illegal CDATA section: " + data);
  592. endStartElement();
  593. writer.write("<![CDATA[");
  594. writer.write(data);
  595. writer.write("]]>");
  596. }
  597. catch (IOException e)
  598. {
  599. XMLStreamException e2 = new XMLStreamException(e);
  600. e2.initCause(e);
  601. throw e2;
  602. }
  603. }
  604. public void writeDTD(String dtd)
  605. throws XMLStreamException
  606. {
  607. try
  608. {
  609. // XXX: Should we parse the doctypedecl at this point to ensure
  610. // wellformedness?
  611. writer.write("<!DOCTYPE ");
  612. writer.write(dtd);
  613. writer.write('>');
  614. }
  615. catch (IOException e)
  616. {
  617. XMLStreamException e2 = new XMLStreamException(e);
  618. e2.initCause(e);
  619. throw e2;
  620. }
  621. }
  622. public void writeEntityRef(String name)
  623. throws XMLStreamException
  624. {
  625. try
  626. {
  627. if (!isName(name))
  628. throw new IllegalArgumentException("illegal Name: " + name);
  629. endStartElement();
  630. writer.write('&');
  631. writer.write(name);
  632. writer.write(';');
  633. }
  634. catch (IOException e)
  635. {
  636. XMLStreamException e2 = new XMLStreamException(e);
  637. e2.initCause(e);
  638. throw e2;
  639. }
  640. }
  641. public void writeStartDocument()
  642. throws XMLStreamException
  643. {
  644. writeStartDocument(null, null);
  645. }
  646. public void writeStartDocument(String version)
  647. throws XMLStreamException
  648. {
  649. writeStartDocument(null, version);
  650. }
  651. public void writeStartDocument(String encoding, String version)
  652. throws XMLStreamException
  653. {
  654. if (version == null)
  655. version = "1.0";
  656. else if ("1.1".equals(version))
  657. xml11 = true;
  658. encoding = this.encoding; // YES: the parameter must be ignored
  659. if (encoding == null)
  660. encoding = "UTF-8";
  661. if (!"1.0".equals(version) && !"1.1".equals(version))
  662. throw new IllegalArgumentException(version);
  663. try
  664. {
  665. writer.write("<?xml version=\"");
  666. writer.write(version);
  667. writer.write("\" encoding=\"");
  668. writer.write(encoding);
  669. writer.write("\"?>");
  670. writer.write(System.getProperty("line.separator"));
  671. }
  672. catch (IOException e)
  673. {
  674. XMLStreamException e2 = new XMLStreamException(e);
  675. e2.initCause(e);
  676. throw e2;
  677. }
  678. }
  679. public void writeCharacters(String text)
  680. throws XMLStreamException
  681. {
  682. if (text == null)
  683. return;
  684. try
  685. {
  686. if (!isChars(text))
  687. throw new IllegalArgumentException("illegal XML character: " + text);
  688. endStartElement();
  689. if (hasXML11RestrictedChars)
  690. writeEncodedWithRestrictedChars(text, false);
  691. else
  692. writeEncoded(text, false);
  693. }
  694. catch (IOException e)
  695. {
  696. XMLStreamException e2 = new XMLStreamException(e);
  697. e2.initCause(e);
  698. throw e2;
  699. }
  700. }
  701. public void writeCharacters(char[] text, int start, int len)
  702. throws XMLStreamException
  703. {
  704. writeCharacters(new String(text, start, len));
  705. }
  706. public String getPrefix(String uri)
  707. throws XMLStreamException
  708. {
  709. String prefix = namespaces.getPrefix(uri);
  710. if (prefix == null && namespaceContext != null)
  711. prefix = namespaceContext.getPrefix(uri);
  712. return prefix;
  713. }
  714. public void setPrefix(String prefix, String uri)
  715. throws XMLStreamException
  716. {
  717. try
  718. {
  719. if (!isURI(uri))
  720. throw new IllegalArgumentException("illegal URI: " + uri);
  721. if (!isPrefix(prefix))
  722. throw new IllegalArgumentException("illegal NCName: " + prefix);
  723. }
  724. catch (IOException e)
  725. {
  726. XMLStreamException e2 = new XMLStreamException(e);
  727. e2.initCause(e);
  728. throw e2;
  729. }
  730. if (!namespaces.declarePrefix(prefix, uri))
  731. throw new XMLStreamException("illegal prefix " + prefix);
  732. }
  733. public void setDefaultNamespace(String uri)
  734. throws XMLStreamException
  735. {
  736. if (!isURI(uri))
  737. throw new IllegalArgumentException("illegal URI: " + uri);
  738. if (!namespaces.declarePrefix(XMLConstants.DEFAULT_NS_PREFIX, uri))
  739. throw new XMLStreamException("illegal default namespace prefix");
  740. }
  741. public void setNamespaceContext(NamespaceContext context)
  742. throws XMLStreamException
  743. {
  744. namespaceContext = context;
  745. }
  746. public NamespaceContext getNamespaceContext()
  747. {
  748. return namespaceContext;
  749. }
  750. public Object getProperty(String name)
  751. throws IllegalArgumentException
  752. {
  753. throw new IllegalArgumentException(name);
  754. }
  755. /**
  756. * Write the specified text, ensuring that the content is suitably encoded
  757. * for XML.
  758. * @param text the text to write
  759. * @param inAttr whether we are in an attribute value
  760. */
  761. private void writeEncoded(String text, boolean inAttr)
  762. throws IOException
  763. {
  764. char[] chars = text.toCharArray();
  765. int start = 0;
  766. int end = chars.length;
  767. int len = 0;
  768. for (int i = start; i < end; i++)
  769. {
  770. char c = chars[i];
  771. if (c == '<' || c == '>' || c == '&')
  772. {
  773. writer.write(chars, start, len);
  774. if (c == '<')
  775. writer.write("&lt;");
  776. else if (c == '>')
  777. writer.write("&gt;");
  778. else
  779. writer.write("&amp;");
  780. start = i + 1;
  781. len = 0;
  782. }
  783. else if (inAttr && (c == '"' || c == '\''))
  784. {
  785. writer.write(chars, start, len);
  786. if (c == '"')
  787. writer.write("&quot;");
  788. else
  789. writer.write("&apos;");
  790. start = i + 1;
  791. len = 0;
  792. }
  793. else
  794. len++;
  795. }
  796. if (len > 0)
  797. writer.write(chars, start, len);
  798. }
  799. /**
  800. * Writes the specified text, in the knowledge that some of the
  801. * characters are XML 1.1 restricted characters.
  802. */
  803. private void writeEncodedWithRestrictedChars(String text, boolean inAttr)
  804. throws IOException
  805. {
  806. int[] seq = UnicodeReader.toCodePointArray(text);
  807. for (int i = 0; i < seq.length; i++)
  808. {
  809. int c = seq[i];
  810. switch (c)
  811. {
  812. case 0x3c: // '<'
  813. writer.write("&lt;");
  814. break;
  815. case 0x3e: // '>'
  816. writer.write("&gt;");
  817. break;
  818. case 0x26: // '&'
  819. writer.write("&amp;");
  820. break;
  821. case 0x22: // '"'
  822. if (inAttr)
  823. writer.write("&quot;");
  824. else
  825. writer.write(c);
  826. break;
  827. case 0x27: // '\''
  828. if (inAttr)
  829. writer.write("&apos;");
  830. else
  831. writer.write(c);
  832. break;
  833. default:
  834. if (XMLParser.isXML11RestrictedChar(c))
  835. writer.write("&#x" + Integer.toHexString(c) + ";");
  836. else
  837. {
  838. char[] chars = Character.toChars(c);
  839. writer.write(chars, 0, chars.length);
  840. }
  841. }
  842. }
  843. }
  844. private boolean isName(String text)
  845. throws IOException
  846. {
  847. if (text == null)
  848. return false;
  849. int[] seq = UnicodeReader.toCodePointArray(text);
  850. if (seq.length < 1)
  851. return false;
  852. if (!XMLParser.isNameStartCharacter(seq[0], xml11))
  853. return false;
  854. for (int i = 1; i < seq.length; i++)
  855. {
  856. if (!XMLParser.isNameCharacter(seq[i], xml11))
  857. return false;
  858. }
  859. return true;
  860. }
  861. private boolean isPrefix(String text)
  862. throws IOException
  863. {
  864. if (XMLConstants.DEFAULT_NS_PREFIX.equals(text)) {
  865. return true;
  866. }
  867. return isNCName(text);
  868. }
  869. private boolean isNCName(String text)
  870. throws IOException
  871. {
  872. if (text == null)
  873. return false;
  874. int[] seq = UnicodeReader.toCodePointArray(text);
  875. if (seq.length < 1)
  876. return false;
  877. if (!XMLParser.isNameStartCharacter(seq[0], xml11) || seq[0] == 0x3a)
  878. return false;
  879. for (int i = 1; i < seq.length; i++)
  880. {
  881. if (!XMLParser.isNameCharacter(seq[i], xml11) || seq[i] == 0x3a)
  882. return false;
  883. }
  884. return true;
  885. }
  886. private boolean isChars(String text)
  887. throws IOException
  888. {
  889. if (text == null)
  890. return false;
  891. int[] seq = UnicodeReader.toCodePointArray(text);
  892. hasXML11RestrictedChars = false;
  893. if (xml11)
  894. {
  895. for (int i = 0; i < seq.length; i++)
  896. {
  897. if (!XMLParser.isXML11Char(seq[i]))
  898. return false;
  899. if (XMLParser.isXML11RestrictedChar(seq[i]))
  900. hasXML11RestrictedChars = true;
  901. }
  902. }
  903. else
  904. {
  905. for (int i = 0; i < seq.length; i++)
  906. {
  907. if (!XMLParser.isChar(seq[i]))
  908. return false;
  909. }
  910. }
  911. return true;
  912. }
  913. private boolean isURI(String text)
  914. {
  915. if (text == null)
  916. return false;
  917. char[] chars = text.toCharArray();
  918. if (chars.length < 1)
  919. return false;
  920. for (int i = 0; i < chars.length; i++)
  921. {
  922. if (chars[i] < 0x20 || chars[i] >= 0x7f)
  923. return false;
  924. }
  925. return true;
  926. }
  927. }