Desktop tool for browsing account info from EVE-Online
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

JDOMResult.java 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. /*--
  2. $Id: JDOMResult.java,v 1.24 2007/11/10 05:29:02 jhunter Exp $
  3. Copyright (C) 2001-2007 Jason Hunter & Brett McLaughlin.
  4. All rights reserved.
  5. Redistribution and use in source and binary forms, with or without
  6. modification, are permitted provided that the following conditions
  7. are met:
  8. 1. Redistributions of source code must retain the above copyright
  9. notice, this list of conditions, and the following disclaimer.
  10. 2. Redistributions in binary form must reproduce the above copyright
  11. notice, this list of conditions, and the disclaimer that follows
  12. these conditions in the documentation and/or other materials
  13. provided with the distribution.
  14. 3. The name "JDOM" must not be used to endorse or promote products
  15. derived from this software without prior written permission. For
  16. written permission, please contact <request_AT_jdom_DOT_org>.
  17. 4. Products derived from this software may not be called "JDOM", nor
  18. may "JDOM" appear in their name, without prior written permission
  19. from the JDOM Project Management <request_AT_jdom_DOT_org>.
  20. In addition, we request (but do not require) that you include in the
  21. end-user documentation provided with the redistribution and/or in the
  22. software itself an acknowledgement equivalent to the following:
  23. "This product includes software developed by the
  24. JDOM Project (http://www.jdom.org/)."
  25. Alternatively, the acknowledgment may be graphical using the logos
  26. available at http://www.jdom.org/images/logos.
  27. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  28. WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  29. OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  30. DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
  31. CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  32. SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  33. LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  34. USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  35. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  36. OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  37. OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  38. SUCH DAMAGE.
  39. This software consists of voluntary contributions made by many
  40. individuals on behalf of the JDOM Project and was originally
  41. created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
  42. Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
  43. on the JDOM Project, please see <http://www.jdom.org/>.
  44. */
  45. package org.jdom.transform;
  46. import java.util.*;
  47. import javax.xml.transform.sax.*;
  48. import org.jdom.*;
  49. import org.jdom.input.*;
  50. import org.xml.sax.*;
  51. import org.xml.sax.ext.*;
  52. import org.xml.sax.helpers.*;
  53. /**
  54. * A holder for an XSL Transformation result, generally a list of nodes
  55. * although it can be a JDOM Document also. As stated by the XSLT 1.0
  56. * specification, the result tree generated by an XSL transformation is not
  57. * required to be a well-formed XML document. The result tree may have "any
  58. * sequence of nodes as children that would be possible for an
  59. * element node".
  60. * <p>
  61. * The following example shows how to apply an XSL Transformation
  62. * to a JDOM document and get the transformation result in the form
  63. * of a list of JDOM nodes:
  64. * <pre><code>
  65. * public static List transform(Document doc, String stylesheet)
  66. * throws JDOMException {
  67. * try {
  68. * Transformer transformer = TransformerFactory.newInstance()
  69. * .newTransformer(new StreamSource(stylesheet));
  70. * JDOMSource in = new JDOMSource(doc);
  71. * JDOMResult out = new JDOMResult();
  72. * transformer.transform(in, out);
  73. * return out.getResult();
  74. * }
  75. * catch (TransformerException e) {
  76. * throw new JDOMException("XSLT Transformation failed", e);
  77. * }
  78. * }
  79. * </code></pre>
  80. *
  81. * @see org.jdom.transform.JDOMSource
  82. *
  83. * @version $Revision: 1.24 $, $Date: 2007/11/10 05:29:02 $
  84. * @author Laurent Bihanic
  85. * @author Jason Hunter
  86. */
  87. public class JDOMResult extends SAXResult {
  88. private static final String CVS_ID =
  89. "@(#) $RCSfile: JDOMResult.java,v $ $Revision: 1.24 $ $Date: 2007/11/10 05:29:02 $ $Name: jdom_1_1 $";
  90. /**
  91. * If {@link javax.xml.transform.TransformerFactory#getFeature}
  92. * returns <code>true</code> when passed this value as an
  93. * argument, the Transformer natively supports JDOM.
  94. * <p>
  95. * <strong>Note</strong>: This implementation does not override
  96. * the {@link SAXResult#FEATURE} value defined by its superclass
  97. * to be considered as a SAXResult by Transformer implementations
  98. * not natively supporting JDOM.</p>
  99. */
  100. public final static String JDOM_FEATURE =
  101. "http://org.jdom.transform.JDOMResult/feature";
  102. /**
  103. * The result of a transformation, as set by Transformer
  104. * implementations that natively support JDOM, as a JDOM document
  105. * or a list of JDOM nodes.
  106. */
  107. private Object result = null;
  108. /**
  109. * Whether the application queried the result (as a list or a
  110. * document) since it was last set.
  111. */
  112. private boolean queried = false;
  113. /**
  114. * The custom JDOM factory to use when building the transformation
  115. * result or <code>null</code> to use the default JDOM classes.
  116. */
  117. private JDOMFactory factory = null;
  118. /**
  119. * Public default constructor.
  120. */
  121. public JDOMResult() {
  122. // Allocate custom builder object...
  123. DocumentBuilder builder = new DocumentBuilder();
  124. // And use it as ContentHandler and LexicalHandler.
  125. super.setHandler(builder);
  126. super.setLexicalHandler(builder);
  127. }
  128. /**
  129. * Sets the object(s) produced as result of an XSL Transformation.
  130. * <p>
  131. * <strong>Note</strong>: This method shall be used by the
  132. * {@link javax.xml.transform.Transformer} implementations that
  133. * natively support JDOM to directly set the transformation
  134. * result rather than considering this object as a
  135. * {@link SAXResult}. Applications should <i>not</i> use this
  136. * method.</p>
  137. *
  138. * @param result the result of a transformation as a
  139. * {@link java.util.List list} of JDOM nodes
  140. * (Elements, Texts, Comments, PIs...).
  141. *
  142. * @see #getResult
  143. */
  144. public void setResult(List result) {
  145. this.result = result;
  146. this.queried = false;
  147. }
  148. /**
  149. * Returns the result of an XSL Transformation as a list of JDOM
  150. * nodes.
  151. * <p>
  152. * If the result of the transformation is a JDOM document,
  153. * this method converts it into a list of JDOM nodes; any
  154. * subsequent call to {@link #getDocument} will return
  155. * <code>null</code>.</p>
  156. *
  157. * @return the transformation result as a (possibly empty) list of
  158. * JDOM nodes (Elements, Texts, Comments, PIs...).
  159. */
  160. public List getResult() {
  161. List nodes = Collections.EMPTY_LIST;
  162. // Retrieve result from the document builder if not set.
  163. this.retrieveResult();
  164. if (result instanceof List) {
  165. nodes = (List)result;
  166. }
  167. else {
  168. if ((result instanceof Document) && (queried == false)) {
  169. List content = ((Document)result).getContent();
  170. nodes = new ArrayList(content.size());
  171. while (content.size() != 0)
  172. {
  173. Object o = content.remove(0);
  174. nodes.add(o);
  175. }
  176. result = nodes;
  177. }
  178. }
  179. queried = true;
  180. return (nodes);
  181. }
  182. /**
  183. * Sets the document produced as result of an XSL Transformation.
  184. * <p>
  185. * <strong>Note</strong>: This method shall be used by the
  186. * {@link javax.xml.transform.Transformer} implementations that
  187. * natively support JDOM to directly set the transformation
  188. * result rather than considering this object as a
  189. * {@link SAXResult}. Applications should <i>not</i> use this
  190. * method.</p>
  191. *
  192. * @param document the JDOM document result of a transformation.
  193. *
  194. * @see #setResult
  195. * @see #getDocument
  196. */
  197. public void setDocument(Document document) {
  198. this.result = document;
  199. this.queried = false;
  200. }
  201. /**
  202. * Returns the result of an XSL Transformation as a JDOM document.
  203. * <p>
  204. * If the result of the transformation is a list of nodes,
  205. * this method attempts to convert it into a JDOM document. If
  206. * successful, any subsequent call to {@link #getResult} will
  207. * return an empty list.</p>
  208. * <p>
  209. * <strong>Warning</strong>: The XSLT 1.0 specification states that
  210. * the output of an XSL transformation is not a well-formed XML
  211. * document but a list of nodes. Applications should thus use
  212. * {@link #getResult} instead of this method or at least expect
  213. * <code>null</code> documents to be returned.
  214. *
  215. * @return the transformation result as a JDOM document or
  216. * <code>null</code> if the result of the transformation
  217. * can not be converted into a well-formed document.
  218. *
  219. * @see #getResult
  220. */
  221. public Document getDocument() {
  222. Document doc = null;
  223. // Retrieve result from the document builder if not set.
  224. this.retrieveResult();
  225. if (result instanceof Document) {
  226. doc = (Document)result;
  227. }
  228. else {
  229. if ((result instanceof List) && (queried == false)) {
  230. // Try to create a document from the result nodes
  231. try {
  232. JDOMFactory f = this.getFactory();
  233. if (f == null) { f = new DefaultJDOMFactory(); }
  234. doc = f.document(null);
  235. doc.setContent((List)result);
  236. result = doc;
  237. }
  238. catch (RuntimeException ex1) {
  239. // Some of the result nodes are not valid children of a
  240. // Document node. => return null.
  241. }
  242. }
  243. }
  244. queried = true;
  245. return (doc);
  246. }
  247. /**
  248. * Sets a custom JDOMFactory to use when building the
  249. * transformation result. Use a custom factory to build the tree
  250. * with your own subclasses of the JDOM classes.
  251. *
  252. * @param factory the custom <code>JDOMFactory</code> to use or
  253. * <code>null</code> to use the default JDOM
  254. * classes.
  255. *
  256. * @see #getFactory
  257. */
  258. public void setFactory(JDOMFactory factory) {
  259. this.factory = factory;
  260. }
  261. /**
  262. * Returns the custom JDOMFactory used to build the transformation
  263. * result.
  264. *
  265. * @return the custom <code>JDOMFactory</code> used to build the
  266. * transformation result or <code>null</code> if the
  267. * default JDOM classes are being used.
  268. *
  269. * @see #setFactory
  270. */
  271. public JDOMFactory getFactory() {
  272. return this.factory;
  273. }
  274. /**
  275. * Checks whether a transformation result has been set and, if not,
  276. * retrieves the result tree being built by the document builder.
  277. */
  278. private void retrieveResult() {
  279. if (result == null) {
  280. this.setResult(((DocumentBuilder)this.getHandler()).getResult());
  281. }
  282. }
  283. //-------------------------------------------------------------------------
  284. // SAXResult overwritten methods
  285. //-------------------------------------------------------------------------
  286. /**
  287. * Sets the target to be a SAX2 ContentHandler.
  288. *
  289. * @param handler Must be a non-null ContentHandler reference.
  290. */
  291. public void setHandler(ContentHandler handler) { }
  292. /**
  293. * Sets the SAX2 LexicalHandler for the output.
  294. * <p>
  295. * This is needed to handle XML comments and the like. If the
  296. * lexical handler is not set, an attempt should be made by the
  297. * transformer to cast the ContentHandler to a LexicalHandler.</p>
  298. *
  299. * @param handler A non-null LexicalHandler for
  300. * handling lexical parse events.
  301. */
  302. public void setLexicalHandler(LexicalHandler handler) { }
  303. //=========================================================================
  304. // FragmentHandler nested class
  305. //=========================================================================
  306. private static class FragmentHandler extends SAXHandler {
  307. /**
  308. * A dummy root element required by SAXHandler that can only
  309. * cope with well-formed documents.
  310. */
  311. private Element dummyRoot = new Element("root", null, null);
  312. /**
  313. * Public constructor.
  314. */
  315. public FragmentHandler(JDOMFactory factory) {
  316. super(factory);
  317. // Add a dummy root element to the being-built document as XSL
  318. // transformation can output node lists instead of well-formed
  319. // documents.
  320. this.pushElement(dummyRoot);
  321. }
  322. /**
  323. * Returns the result of an XSL Transformation.
  324. *
  325. * @return the transformation result as a (possibly empty) list of
  326. * JDOM nodes (Elements, Texts, Comments, PIs...).
  327. */
  328. public List getResult() {
  329. // Flush remaining text content in case the last text segment is
  330. // outside an element.
  331. try {
  332. this.flushCharacters();
  333. }
  334. catch (SAXException e) { /* Ignore... */ }
  335. return this.getDetachedContent(dummyRoot);
  336. }
  337. /**
  338. * Returns the content of a JDOM Element detached from it.
  339. *
  340. * @param elt the element to get the content from.
  341. *
  342. * @return a (possibly empty) list of JDOM nodes, detached from
  343. * their parent.
  344. */
  345. private List getDetachedContent(Element elt) {
  346. List content = elt.getContent();
  347. List nodes = new ArrayList(content.size());
  348. while (content.size() != 0)
  349. {
  350. Object o = content.remove(0);
  351. nodes.add(o);
  352. }
  353. return (nodes);
  354. }
  355. }
  356. //=========================================================================
  357. // DocumentBuilder inner class
  358. //=========================================================================
  359. private class DocumentBuilder extends XMLFilterImpl
  360. implements LexicalHandler {
  361. /**
  362. * The actual JDOM document builder.
  363. */
  364. private FragmentHandler saxHandler = null;
  365. /**
  366. * Whether the startDocument event was received. Some XSLT
  367. * processors such as Oracle's do not fire this event.
  368. */
  369. private boolean startDocumentReceived = false;
  370. /**
  371. * Public default constructor.
  372. */
  373. public DocumentBuilder() { }
  374. /**
  375. * Returns the result of an XSL Transformation.
  376. *
  377. * @return the transformation result as a (possibly empty) list of
  378. * JDOM nodes (Elements, Texts, Comments, PIs...) or
  379. * <code>null</code> if no new transformation occurred
  380. * since the result of the previous one was returned.
  381. */
  382. public List getResult() {
  383. List result = null;
  384. if (this.saxHandler != null) {
  385. // Retrieve result from SAX content handler.
  386. result = this.saxHandler.getResult();
  387. // Detach the (non-reusable) SAXHandler instance.
  388. this.saxHandler = null;
  389. // And get ready for the next transformation.
  390. this.startDocumentReceived = false;
  391. }
  392. return result;
  393. }
  394. private void ensureInitialization() throws SAXException {
  395. // Trigger document initialization if XSLT processor failed to
  396. // fire the startDocument event.
  397. if (this.startDocumentReceived == false) {
  398. this.startDocument();
  399. }
  400. }
  401. //-----------------------------------------------------------------------
  402. // XMLFilterImpl overwritten methods
  403. //-----------------------------------------------------------------------
  404. /**
  405. * <i>[SAX ContentHandler interface support]</i> Processes a
  406. * start of document event.
  407. * <p>
  408. * This implementation creates a new JDOM document builder and
  409. * marks the current result as "under construction".</p>
  410. *
  411. * @throws SAXException if any error occurred while creating
  412. * the document builder.
  413. */
  414. public void startDocument() throws SAXException {
  415. this.startDocumentReceived = true;
  416. // Reset any previously set result.
  417. setResult(null);
  418. // Create the actual JDOM document builder and register it as
  419. // ContentHandler on the superclass (XMLFilterImpl): this
  420. // implementation will take care of propagating the LexicalHandler
  421. // events.
  422. this.saxHandler = new FragmentHandler(getFactory());
  423. super.setContentHandler(this.saxHandler);
  424. // And propagate event.
  425. super.startDocument();
  426. }
  427. /**
  428. * <i>[SAX ContentHandler interface support]</i> Receives
  429. * notification of the beginning of an element.
  430. * <p>
  431. * This implementation ensures that startDocument() has been
  432. * called prior processing an element.
  433. *
  434. * @param nsURI the Namespace URI, or the empty string if
  435. * the element has no Namespace URI or if
  436. * Namespace processing is not being performed.
  437. * @param localName the local name (without prefix), or the
  438. * empty string if Namespace processing is
  439. * not being performed.
  440. * @param qName the qualified name (with prefix), or the
  441. * empty string if qualified names are not
  442. * available.
  443. * @param atts The attributes attached to the element. If
  444. * there are no attributes, it shall be an
  445. * empty Attributes object.
  446. *
  447. * @throws SAXException if any error occurred while creating
  448. * the document builder.
  449. */
  450. public void startElement(String nsURI, String localName, String qName,
  451. Attributes atts) throws SAXException
  452. {
  453. this.ensureInitialization();
  454. super.startElement(nsURI, localName, qName, atts);
  455. }
  456. /**
  457. * <i>[SAX ContentHandler interface support]</i> Begins the
  458. * scope of a prefix-URI Namespace mapping.
  459. */
  460. public void startPrefixMapping(String prefix, String uri)
  461. throws SAXException {
  462. this.ensureInitialization();
  463. super.startPrefixMapping(prefix, uri);
  464. }
  465. /**
  466. * <i>[SAX ContentHandler interface support]</i> Receives
  467. * notification of character data.
  468. */
  469. public void characters(char ch[], int start, int length)
  470. throws SAXException {
  471. this.ensureInitialization();
  472. super.characters(ch, start, length);
  473. }
  474. /**
  475. * <i>[SAX ContentHandler interface support]</i> Receives
  476. * notification of ignorable whitespace in element content.
  477. */
  478. public void ignorableWhitespace(char ch[], int start, int length)
  479. throws SAXException {
  480. this.ensureInitialization();
  481. super.ignorableWhitespace(ch, start, length);
  482. }
  483. /**
  484. * <i>[SAX ContentHandler interface support]</i> Receives
  485. * notification of a processing instruction.
  486. */
  487. public void processingInstruction(String target, String data)
  488. throws SAXException {
  489. this.ensureInitialization();
  490. super.processingInstruction(target, data);
  491. }
  492. /**
  493. * <i>[SAX ContentHandler interface support]</i> Receives
  494. * notification of a skipped entity.
  495. */
  496. public void skippedEntity(String name) throws SAXException {
  497. this.ensureInitialization();
  498. super.skippedEntity(name);
  499. }
  500. //-----------------------------------------------------------------------
  501. // LexicalHandler interface support
  502. //-----------------------------------------------------------------------
  503. /**
  504. * <i>[SAX LexicalHandler interface support]</i> Reports the
  505. * start of DTD declarations, if any.
  506. *
  507. * @param name the document type name.
  508. * @param publicId the declared public identifier for the
  509. * external DTD subset, or <code>null</code>
  510. * if none was declared.
  511. * @param systemId the declared system identifier for the
  512. * external DTD subset, or <code>null</code>
  513. * if none was declared.
  514. *
  515. * @throws SAXException The application may raise an exception.
  516. */
  517. public void startDTD(String name, String publicId, String systemId)
  518. throws SAXException {
  519. this.ensureInitialization();
  520. this.saxHandler.startDTD(name, publicId, systemId);
  521. }
  522. /**
  523. * <i>[SAX LexicalHandler interface support]</i> Reports the end
  524. * of DTD declarations.
  525. *
  526. * @throws SAXException The application may raise an exception.
  527. */
  528. public void endDTD() throws SAXException {
  529. this.saxHandler.endDTD();
  530. }
  531. /**
  532. * <i>[SAX LexicalHandler interface support]</i> Reports the
  533. * beginning of some internal and external XML entities.
  534. *
  535. * @param name the name of the entity. If it is a parameter
  536. * entity, the name will begin with '%', and if it
  537. * is the external DTD subset, it will be "[dtd]".
  538. *
  539. * @throws SAXException The application may raise an exception.
  540. */
  541. public void startEntity(String name) throws SAXException {
  542. this.ensureInitialization();
  543. this.saxHandler.startEntity(name);
  544. }
  545. /**
  546. * <i>[SAX LexicalHandler interface support]</i> Reports the end
  547. * of an entity.
  548. *
  549. * @param name the name of the entity that is ending.
  550. *
  551. * @throws SAXException The application may raise an exception.
  552. */
  553. public void endEntity(String name) throws SAXException {
  554. this.saxHandler.endEntity(name);
  555. }
  556. /**
  557. * <i>[SAX LexicalHandler interface support]</i> Reports the
  558. * start of a CDATA section.
  559. *
  560. * @throws SAXException The application may raise an exception.
  561. */
  562. public void startCDATA() throws SAXException {
  563. this.ensureInitialization();
  564. this.saxHandler.startCDATA();
  565. }
  566. /**
  567. * <i>[SAX LexicalHandler interface support]</i> Reports the end
  568. * of a CDATA section.
  569. *
  570. * @throws SAXException The application may raise an exception.
  571. */
  572. public void endCDATA() throws SAXException {
  573. this.saxHandler.endCDATA();
  574. }
  575. /**
  576. * <i>[SAX LexicalHandler interface support]</i> Reports an XML
  577. * comment anywhere in the document.
  578. *
  579. * @param ch an array holding the characters in the comment.
  580. * @param start the starting position in the array.
  581. * @param length the number of characters to use from the array.
  582. *
  583. * @throws SAXException The application may raise an exception.
  584. */
  585. public void comment(char ch[], int start, int length)
  586. throws SAXException {
  587. this.ensureInitialization();
  588. this.saxHandler.comment(ch, start, length);
  589. }
  590. }
  591. }