1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Xalan" and "Apache Software Foundation" must
  28. * not be used to endorse or promote products derived from this
  29. * software without prior written permission. For written
  30. * permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * nor may "Apache" appear in their name, without prior written
  34. * permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation and was
  52. * originally based on software copyright (c) 1999, Lotus
  53. * Development Corporation., http://www.lotus.com. For more
  54. * information on the Apache Software Foundation, please see
  55. * <http://www.apache.org/>.
  56. */
  57. package org.apache.xalan.transformer;
  58. import java.util.Enumeration;
  59. import org.apache.xalan.processor.StylesheetHandler;
  60. import org.apache.xalan.res.XSLTErrorResources;
  61. import org.apache.xalan.templates.Stylesheet;
  62. import org.apache.xalan.templates.StylesheetRoot;
  63. import org.apache.xalan.templates.ElemTemplate;
  64. import org.apache.xalan.templates.ElemTemplateElement;
  65. import org.apache.xalan.trace.TraceManager;
  66. import org.apache.xalan.trace.GenerateEvent;
  67. import org.apache.xml.utils.MutableAttrListImpl;
  68. import org.apache.xml.utils.QName;
  69. import org.apache.xml.utils.TreeWalker;
  70. import org.apache.xml.utils.ObjectPool;
  71. import org.apache.xml.utils.XMLCharacterRecognizer;
  72. import org.apache.xpath.objects.XObject;
  73. import org.apache.xpath.XPathContext;
  74. import org.apache.xml.dtm.DTM;
  75. import org.apache.xml.dtm.DTMIterator;
  76. import org.apache.xml.dtm.DTMFilter;
  77. import org.xml.sax.Attributes;
  78. import org.xml.sax.ContentHandler;
  79. import org.xml.sax.ext.LexicalHandler;
  80. import org.xml.sax.SAXParseException;
  81. import org.xml.sax.SAXException;
  82. import org.xml.sax.ErrorHandler;
  83. import org.xml.sax.helpers.NamespaceSupport;
  84. import org.apache.xml.utils.NamespaceSupport2;
  85. import org.xml.sax.Locator;
  86. import javax.xml.transform.TransformerException;
  87. import javax.xml.transform.ErrorListener;
  88. import javax.xml.transform.Transformer;
  89. /**
  90. * This class is a layer between the direct calls to the result
  91. * tree content handler, and the transformer. For one thing,
  92. * we have to delay the call to
  93. * getContentHandler().startElement(name, atts) because of the
  94. * xsl:attribute and xsl:copy calls. In other words,
  95. * the attributes have to be fully collected before you
  96. * can call startElement.
  97. */
  98. public class ResultTreeHandler extends QueuedEvents
  99. implements ContentHandler, LexicalHandler, TransformState,
  100. org.apache.xml.dtm.ref.dom2dtm.DOM2DTM.CharacterNodeHandler,
  101. ErrorHandler
  102. {
  103. /** Indicate whether running in Debug mode */
  104. private static final boolean DEBUG = false;
  105. /**
  106. * Null constructor for object pooling.
  107. */
  108. public ResultTreeHandler(){}
  109. /**
  110. * Create a new result tree handler. The real content
  111. * handler will be the ContentHandler passed as an argument.
  112. *
  113. * @param transformer non-null transformer instance
  114. * @param realHandler Content Handler instance
  115. */
  116. public ResultTreeHandler(TransformerImpl transformer,
  117. ContentHandler realHandler)
  118. {
  119. init(transformer, realHandler);
  120. }
  121. /**
  122. * Initializer method.
  123. *
  124. * @param transformer non-null transformer instance
  125. * @param realHandler Content Handler instance
  126. */
  127. public void init(TransformerImpl transformer, ContentHandler realHandler)
  128. {
  129. m_transformer = transformer;
  130. // m_startDoc.setTransformer(m_transformer);
  131. TraceManager tracer = transformer.getTraceManager();
  132. if ((null != tracer) && tracer.hasTraceListeners())
  133. m_tracer = tracer;
  134. else
  135. m_tracer = null;
  136. // m_startDoc.setTraceManager(m_tracer);
  137. m_contentHandler = realHandler;
  138. // m_startDoc.setContentHandler(m_contentHandler);
  139. if (m_contentHandler instanceof LexicalHandler)
  140. m_lexicalHandler = (LexicalHandler) m_contentHandler;
  141. else
  142. m_lexicalHandler = null;
  143. m_isTransformClient = (m_contentHandler instanceof TransformerClient);
  144. m_cloner = new ClonerToResultTree(transformer, this);
  145. // The stylesheet is set at a rather late stage, so I do
  146. // this here, though it would probably be better done elsewhere.
  147. if (null != m_transformer)
  148. m_stylesheetRoot = m_transformer.getStylesheet();
  149. pushDocumentEvent(); // not pending yet.
  150. }
  151. /**
  152. * Bottleneck the startDocument event.
  153. *
  154. * @throws org.xml.sax.SAXException
  155. */
  156. public void startDocument() throws org.xml.sax.SAXException{}
  157. /**
  158. * Bottleneck the endDocument event. This may be called
  159. * more than once in order to make sure the pending start
  160. * document is called.
  161. *
  162. * @throws org.xml.sax.SAXException
  163. */
  164. public void endDocument() throws org.xml.sax.SAXException
  165. {
  166. flushPending(true);
  167. if (!m_docEnded)
  168. {
  169. m_contentHandler.endDocument();
  170. if (null != m_tracer)
  171. {
  172. GenerateEvent ge =
  173. new GenerateEvent(m_transformer,
  174. GenerateEvent.EVENTTYPE_ENDDOCUMENT, null);
  175. m_tracer.fireGenerateEvent(ge);
  176. }
  177. m_docEnded = true;
  178. m_docPending = false;
  179. }
  180. }
  181. /**
  182. * Bottleneck the startElement event. This is used to "pend" an
  183. * element, so that attributes can still be added to it before
  184. * the real "startElement" is called on the result tree listener.
  185. *
  186. * @param ns Namespace URI of element
  187. * @param localName Local part of qname of element
  188. * @param name Name of element
  189. * @param atts List of attributes for the element
  190. *
  191. * @throws org.xml.sax.SAXException
  192. */
  193. public void startElement(
  194. String ns, String localName, String name, Attributes atts)
  195. throws org.xml.sax.SAXException
  196. {
  197. if (DEBUG)
  198. {
  199. if (m_elemIsPending)
  200. System.out.println("(ResultTreeHandler#startElement - pended: "
  201. + m_url + "#" + m_localName);
  202. System.out.println("ResultTreeHandler#startElement: " + ns + "#"
  203. + localName);
  204. // if(null == ns)
  205. // {
  206. // (new RuntimeException(localName+" has a null namespace!")).printStackTrace();
  207. // }
  208. }
  209. if(m_docPending)
  210. checkForSerializerSwitch(ns, localName);
  211. flushPending(true);
  212. if (!m_nsContextPushed)
  213. {
  214. if (DEBUG)
  215. System.out.println(
  216. "ResultTreeHandler#startElement - push(startElement)");
  217. m_nsSupport.pushContext();
  218. m_nsContextPushed = true;
  219. }
  220. if (ns != null)
  221. ensurePrefixIsDeclared(ns, name);
  222. m_name = name;
  223. m_url = ns;
  224. m_localName = localName;
  225. if (null != atts)
  226. m_attributes.addAttributes(atts);
  227. m_elemIsPending = true;
  228. m_elemIsEnded = false;
  229. if(m_isTransformClient && (null != m_transformer))
  230. {
  231. m_snapshot.m_currentElement = m_transformer.getCurrentElement();
  232. m_snapshot.m_currentTemplate = m_transformer.getCurrentTemplate();
  233. m_snapshot.m_matchedTemplate = m_transformer.getMatchedTemplate();
  234. int currentNodeHandle = m_transformer.getCurrentNode();
  235. DTM dtm = m_transformer.getXPathContext().getDTM(currentNodeHandle);
  236. m_snapshot.m_currentNode = dtm.getNode(currentNodeHandle);
  237. m_snapshot.m_matchedNode = m_transformer.getMatchedNode();
  238. m_snapshot.m_contextNodeList = m_transformer.getContextNodeList(); // TODO: Need to clone
  239. }
  240. // initQSE(m_startElement);
  241. m_eventCount++;
  242. }
  243. /**
  244. * Bottleneck the endElement event.
  245. *
  246. * @param ns Namespace URI of element
  247. * @param localName Local part of qname of element
  248. * @param name Name of element
  249. *
  250. * @throws org.xml.sax.SAXException
  251. */
  252. public void endElement(String ns, String localName, String name)
  253. throws org.xml.sax.SAXException
  254. {
  255. if (DEBUG)
  256. {
  257. if (m_elemIsPending)
  258. System.out.println("(ResultTreeHandler#endElement - pended: "
  259. + m_url + "#" + m_localName);
  260. System.out.println("ResultTreeHandler#endElement: " + ns + "#"
  261. + localName);
  262. }
  263. flushPending(true);
  264. m_contentHandler.endElement(ns, localName, name);
  265. if (null != m_tracer)
  266. {
  267. GenerateEvent ge = new GenerateEvent(m_transformer,
  268. GenerateEvent.EVENTTYPE_ENDELEMENT,
  269. name, (Attributes)null);
  270. m_tracer.fireGenerateEvent(ge);
  271. }
  272. sendEndPrefixMappings();
  273. popEvent();
  274. if (DEBUG)
  275. System.out.println("ResultTreeHandler#startElement pop: " + localName);
  276. m_nsSupport.popContext();
  277. }
  278. /** Indicate whether a namespace context was pushed */
  279. boolean m_nsContextPushed = false;
  280. /**
  281. * Begin the scope of a prefix-URI Namespace mapping.
  282. *
  283. * <p>The information from this event is not necessary for
  284. * normal Namespace processing: the SAX XML reader will
  285. * automatically replace prefixes for element and attribute
  286. * names when the http://xml.org/sax/features/namespaces
  287. * feature is true (the default).</p>
  288. *
  289. * <p>There are cases, however, when applications need to
  290. * use prefixes in character data or in attribute values,
  291. * where they cannot safely be expanded automatically; the
  292. * start/endPrefixMapping event supplies the information
  293. * to the application to expand prefixes in those contexts
  294. * itself, if necessary.</p>
  295. *
  296. * <p>Note that start/endPrefixMapping events are not
  297. * guaranteed to be properly nested relative to each-other:
  298. * all startPrefixMapping events will occur before the
  299. * corresponding startElement event, and all endPrefixMapping
  300. * events will occur after the corresponding endElement event,
  301. * but their order is not guaranteed.</p>
  302. *
  303. * @param prefix The Namespace prefix being declared.
  304. * @param uri The Namespace URI the prefix is mapped to.
  305. * @throws org.xml.sax.SAXException The client may throw
  306. * an exception during processing.
  307. * @see #endPrefixMapping
  308. * @see #startElement
  309. */
  310. public void startPrefixMapping(String prefix, String uri)
  311. throws org.xml.sax.SAXException
  312. {
  313. startPrefixMapping(prefix, uri, true);
  314. }
  315. /**
  316. * Begin the scope of a prefix-URI Namespace mapping.
  317. *
  318. *
  319. * @param prefix The Namespace prefix being declared.
  320. * @param uri The Namespace URI the prefix is mapped to.
  321. * @param shouldFlush Indicate whether pending events needs
  322. * to be flushed first
  323. *
  324. * @throws org.xml.sax.SAXException The client may throw
  325. * an exception during processing.
  326. */
  327. public void startPrefixMapping(
  328. String prefix, String uri, boolean shouldFlush)
  329. throws org.xml.sax.SAXException
  330. {
  331. if (shouldFlush)
  332. flushPending(false);
  333. if (!m_nsContextPushed)
  334. {
  335. if (DEBUG)
  336. System.out.println(
  337. "ResultTreeHandler#startPrefixMapping push(startPrefixMapping: "
  338. + prefix + ")");
  339. m_nsSupport.pushContext();
  340. m_nsContextPushed = true;
  341. }
  342. if (null == prefix)
  343. prefix = ""; // bit-o-hack, that that's OK
  344. String existingURI = m_nsSupport.getURI(prefix);
  345. if (null == existingURI)
  346. existingURI = "";
  347. if (null == uri)
  348. uri = "";
  349. if (!existingURI.equals(uri))
  350. {
  351. if (DEBUG)
  352. {
  353. System.out.println("ResultTreeHandler#startPrefixMapping Prefix: "
  354. + prefix);
  355. System.out.println("ResultTreeHandler#startPrefixMapping uri: "
  356. + uri);
  357. }
  358. m_nsSupport.declarePrefix(prefix, uri);
  359. }
  360. }
  361. /**
  362. * End the scope of a prefix-URI mapping.
  363. *
  364. * <p>See startPrefixMapping for details. This event will
  365. * always occur after the corresponding endElement event,
  366. * but the order of endPrefixMapping events is not otherwise
  367. * guaranteed.</p>
  368. *
  369. * @param prefix The prefix that was being mapping.
  370. * @throws org.xml.sax.SAXException The client may throw
  371. * an exception during processing.
  372. * @see #startPrefixMapping
  373. * @see #endElement
  374. */
  375. public void endPrefixMapping(String prefix)
  376. throws org.xml.sax.SAXException{}
  377. /**
  378. * Bottleneck the characters event.
  379. *
  380. * @param ch Array of characters to process
  381. * @param start start of characters in the array
  382. * @param length Number of characters in the array
  383. *
  384. * @throws org.xml.sax.SAXException
  385. */
  386. public void characters(char ch[], int start, int length)
  387. throws org.xml.sax.SAXException
  388. {
  389. // It would be nice to suppress all whitespace before the
  390. // first element, but this is going to cause potential problems with
  391. // text serialization and with text entities (right term?).
  392. // So this really needs to be done at the serializer level.
  393. /*if (m_startDoc.isPending
  394. && XMLCharacterRecognizer.isWhiteSpace(ch, start, length))
  395. return;*/
  396. if (DEBUG)
  397. {
  398. System.out.print("ResultTreeHandler#characters: ");
  399. int n = start + length;
  400. for (int i = start; i < n; i++)
  401. {
  402. if (Character.isWhitespace(ch[i]))
  403. System.out.print("\\" + ((int) ch[i]));
  404. else
  405. System.out.print(ch[i]);
  406. }
  407. System.out.println("");
  408. }
  409. flushPending(true);
  410. m_contentHandler.characters(ch, start, length);
  411. if (null != m_tracer)
  412. {
  413. GenerateEvent ge = new GenerateEvent(m_transformer,
  414. GenerateEvent.EVENTTYPE_CHARACTERS,
  415. ch, start, length);
  416. m_tracer.fireGenerateEvent(ge);
  417. }
  418. }
  419. public void characters(org.w3c.dom.Node node)
  420. throws org.xml.sax.SAXException
  421. {
  422. flushPending(true);
  423. if(m_isTransformClient)
  424. m_snapshot.m_currentNode = node;
  425. String data = node.getNodeValue();
  426. char [] ch = null;
  427. int length = 0;
  428. if (data != null)
  429. {
  430. ch = data.toCharArray();
  431. length = data.length();
  432. m_contentHandler.characters(ch, 0, length);
  433. }
  434. if (null != m_tracer)
  435. {
  436. GenerateEvent ge = new GenerateEvent(m_transformer,
  437. GenerateEvent.EVENTTYPE_CHARACTERS,
  438. ch, 0, length);
  439. m_tracer.fireGenerateEvent(ge);
  440. }
  441. if(m_isTransformClient)
  442. m_snapshot.m_currentNode = null;
  443. }
  444. /**
  445. * Bottleneck the ignorableWhitespace event.
  446. *
  447. * @param ch Array of characters to process
  448. * @param start start of characters in the array
  449. * @param length Number of characters in the array
  450. *
  451. * @throws org.xml.sax.SAXException
  452. */
  453. public void ignorableWhitespace(char ch[], int start, int length)
  454. throws org.xml.sax.SAXException
  455. {
  456. if (m_docPending
  457. && XMLCharacterRecognizer.isWhiteSpace(ch, start, length))
  458. return;
  459. flushPending(true);
  460. m_contentHandler.ignorableWhitespace(ch, start, length);
  461. if (null != m_tracer)
  462. {
  463. GenerateEvent ge =
  464. new GenerateEvent(m_transformer,
  465. GenerateEvent.EVENTTYPE_IGNORABLEWHITESPACE, ch,
  466. start, length);
  467. m_tracer.fireGenerateEvent(ge);
  468. }
  469. }
  470. /**
  471. * Bottleneck the processingInstruction event.
  472. *
  473. * @param target Processing instruction target name
  474. * @param data Processing instruction data
  475. *
  476. * @throws org.xml.sax.SAXException
  477. */
  478. public void processingInstruction(String target, String data)
  479. throws org.xml.sax.SAXException
  480. {
  481. flushPending(true);
  482. m_contentHandler.processingInstruction(target, data);
  483. if (null != m_tracer)
  484. {
  485. GenerateEvent ge = new GenerateEvent(m_transformer,
  486. GenerateEvent.EVENTTYPE_PI,
  487. target, data);
  488. m_tracer.fireGenerateEvent(ge);
  489. }
  490. }
  491. /**
  492. * Bottleneck the comment event.
  493. *
  494. * @param data Comment data
  495. *
  496. * @throws org.xml.sax.SAXException
  497. */
  498. public void comment(String data) throws org.xml.sax.SAXException
  499. {
  500. flushPending(true);
  501. if (null != m_lexicalHandler)
  502. {
  503. m_lexicalHandler.comment(data.toCharArray(), 0, data.length());
  504. }
  505. if (null != m_tracer)
  506. {
  507. GenerateEvent ge = new GenerateEvent(m_transformer,
  508. GenerateEvent.EVENTTYPE_COMMENT,
  509. data);
  510. m_tracer.fireGenerateEvent(ge);
  511. }
  512. }
  513. /**
  514. * Bottleneck the comment event.
  515. *
  516. * @param ch Character array with comment data
  517. * @param start start of characters in the array
  518. * @param length number of characters in the array
  519. *
  520. * @throws org.xml.sax.SAXException
  521. */
  522. public void comment(char ch[], int start, int length)
  523. throws org.xml.sax.SAXException
  524. {
  525. flushPending(true);
  526. if (null != m_lexicalHandler)
  527. {
  528. m_lexicalHandler.comment(ch, start, length);
  529. }
  530. if (null != m_tracer)
  531. {
  532. GenerateEvent ge = new GenerateEvent(m_transformer,
  533. GenerateEvent.EVENTTYPE_COMMENT,
  534. new String(ch, start, length));
  535. m_tracer.fireGenerateEvent(ge);
  536. }
  537. }
  538. /**
  539. * Entity reference event.
  540. *
  541. * @param name Name of entity
  542. *
  543. * @throws org.xml.sax.SAXException
  544. */
  545. public void entityReference(String name) throws org.xml.sax.SAXException
  546. {
  547. flushPending(true);
  548. if (null != m_lexicalHandler)
  549. {
  550. m_lexicalHandler.startEntity(name);
  551. m_lexicalHandler.endEntity(name);
  552. }
  553. if (null != m_tracer)
  554. {
  555. GenerateEvent ge = new GenerateEvent(m_transformer,
  556. GenerateEvent.EVENTTYPE_ENTITYREF,
  557. name);
  558. m_tracer.fireGenerateEvent(ge);
  559. }
  560. }
  561. /**
  562. * Start an entity.
  563. *
  564. * @param name Name of the entity
  565. *
  566. * @throws org.xml.sax.SAXException
  567. */
  568. public void startEntity(String name) throws org.xml.sax.SAXException
  569. {
  570. flushPending(true);
  571. if (null != m_lexicalHandler)
  572. {
  573. m_lexicalHandler.startEntity(name);
  574. }
  575. }
  576. /**
  577. * End an entity.
  578. *
  579. * @param name Name of the entity
  580. *
  581. * @throws org.xml.sax.SAXException
  582. */
  583. public void endEntity(String name) throws org.xml.sax.SAXException
  584. {
  585. flushPending(true);
  586. if (null != m_lexicalHandler)
  587. {
  588. m_lexicalHandler.endEntity(name);
  589. }
  590. if (null != m_tracer)
  591. {
  592. GenerateEvent ge = new GenerateEvent(m_transformer,
  593. GenerateEvent.EVENTTYPE_ENTITYREF,
  594. name);
  595. m_tracer.fireGenerateEvent(ge);
  596. }
  597. }
  598. /**
  599. * Start the DTD.
  600. *
  601. * @param s1 The document type name.
  602. * @param s2 The declared public identifier for the
  603. * external DTD subset, or null if none was declared.
  604. * @param s3 The declared system identifier for the
  605. * external DTD subset, or null if none was declared.
  606. *
  607. * @throws org.xml.sax.SAXException
  608. */
  609. public void startDTD(String s1, String s2, String s3)
  610. throws org.xml.sax.SAXException
  611. {
  612. flushPending(true);
  613. if (null != m_lexicalHandler)
  614. {
  615. m_lexicalHandler.startDTD(s1, s2, s3);
  616. }
  617. }
  618. /**
  619. * End the DTD.
  620. *
  621. * @throws org.xml.sax.SAXException
  622. */
  623. public void endDTD() throws org.xml.sax.SAXException
  624. {
  625. flushPending(true);
  626. if (null != m_lexicalHandler)
  627. {
  628. m_lexicalHandler.endDTD();
  629. }
  630. }
  631. /**
  632. * Start the CDATACharacters.
  633. *
  634. * @throws org.xml.sax.SAXException
  635. */
  636. public void startCDATA() throws org.xml.sax.SAXException
  637. {
  638. flushPending(true);
  639. if (null != m_lexicalHandler)
  640. {
  641. m_lexicalHandler.startCDATA();
  642. }
  643. }
  644. /**
  645. * End the CDATA characters.
  646. *
  647. * @throws org.xml.sax.SAXException
  648. */
  649. public void endCDATA() throws org.xml.sax.SAXException
  650. {
  651. flushPending(true);
  652. if (null != m_lexicalHandler)
  653. {
  654. m_lexicalHandler.endCDATA();
  655. }
  656. }
  657. /**
  658. * Receive notification of a skipped entity.
  659. *
  660. * <p>The Parser will invoke this method once for each entity
  661. * skipped. Non-validating processors may skip entities if they
  662. * have not seen the declarations (because, for example, the
  663. * entity was declared in an external DTD subset). All processors
  664. * may skip external entities, depending on the values of the
  665. * http://xml.org/sax/features/external-general-entities and the
  666. * http://xml.org/sax/features/external-parameter-entities
  667. * properties.</p>
  668. *
  669. * @param name The name of the skipped entity. If it is a
  670. * parameter entity, the name will begin with '%'.
  671. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  672. * wrapping another exception.
  673. */
  674. public void skippedEntity(String name) throws org.xml.sax.SAXException{}
  675. /**
  676. * Set whether Namespace declarations have been added to
  677. * this element
  678. *
  679. *
  680. * @param b Flag indicating whether Namespace declarations
  681. * have been added to this element
  682. */
  683. public void setNSDeclsHaveBeenAdded(boolean b)
  684. {
  685. m_nsDeclsHaveBeenAdded = b;
  686. }
  687. /**
  688. * Flush the event.
  689. *
  690. * @throws TransformerException
  691. *
  692. * @throws org.xml.sax.SAXException
  693. */
  694. void flushDocEvent() throws org.xml.sax.SAXException
  695. {
  696. if (m_docPending)
  697. {
  698. m_contentHandler.startDocument();
  699. if (null != m_tracer)
  700. {
  701. GenerateEvent ge =
  702. new GenerateEvent(m_transformer,
  703. GenerateEvent.EVENTTYPE_STARTDOCUMENT);
  704. m_tracer.fireGenerateEvent(ge);
  705. }
  706. if (m_contentHandler instanceof TransformerClient)
  707. {
  708. ((TransformerClient) m_contentHandler).setTransformState(this);
  709. }
  710. m_docPending = false;
  711. }
  712. }
  713. /**
  714. * Flush the event.
  715. *
  716. * @throws SAXException
  717. */
  718. void flushElem() throws org.xml.sax.SAXException
  719. {
  720. if (m_elemIsPending)
  721. {
  722. if (null != m_name)
  723. {
  724. try
  725. {
  726. m_contentHandler.startElement(m_url, m_localName, m_name,
  727. m_attributes);
  728. }
  729. catch(Exception re)
  730. {
  731. // If we don't do this, and the exception is a RuntimeException,
  732. // good line numbers of where the exception occured in the stylesheet
  733. // won't get reported. I tried just catching RuntimeException, but
  734. // for whatever reason it didn't seem to catch.
  735. // Fix for Christina's DOMException error problem.
  736. throw new SAXParseException(re.getMessage(),
  737. m_transformer.getCurrentElement().getPublicId(),
  738. m_transformer.getCurrentElement().getSystemId(),
  739. m_transformer.getCurrentElement().getLineNumber(),
  740. m_transformer.getCurrentElement().getColumnNumber(),
  741. re);
  742. }
  743. if(null != m_tracer)
  744. {
  745. GenerateEvent ge =
  746. new GenerateEvent(m_transformer,
  747. GenerateEvent.EVENTTYPE_STARTELEMENT, m_name,
  748. m_attributes);
  749. m_tracer.fireGenerateEvent(ge);
  750. }
  751. if(m_isTransformClient)
  752. m_snapshot.m_currentNode = null;
  753. }
  754. m_elemIsPending = false;
  755. m_attributes.clear();
  756. m_nsDeclsHaveBeenAdded = false;
  757. m_name = null;
  758. m_url = null;
  759. m_localName = null;
  760. m_namespaces = null;
  761. // super.flush();
  762. }
  763. }
  764. /**
  765. * Flush the pending element.
  766. *
  767. * @throws org.xml.sax.SAXException
  768. */
  769. public final void flushPending() throws org.xml.sax.SAXException
  770. {
  771. flushPending(true);
  772. }
  773. /**
  774. * Flush the pending element, and any attributes associated with it.
  775. *
  776. * NOTE: If there are attributes but _no_ pending element (which can
  777. * happen if the user's stylesheet is doing something inappropriate),
  778. * we still want to make sure they are flushed.
  779. *
  780. * @param type Event type
  781. *
  782. * NEEDSDOC @param flushPrefixes
  783. *
  784. * @throws org.xml.sax.SAXException
  785. */
  786. public final void flushPending(boolean flushPrefixes)
  787. throws org.xml.sax.SAXException
  788. {
  789. if (flushPrefixes && m_docPending)
  790. {
  791. flushDocEvent();
  792. }
  793. if (m_elemIsPending)
  794. {
  795. // Combined loop shoud be much more efficient.
  796. // %REVIEW% %OPT% Will the "else" case ever arise?
  797. if (!m_nsDeclsHaveBeenAdded)
  798. // addNSDeclsToAttrs();
  799. startAndAddPrefixMappings(); // new
  800. else // new
  801. sendStartPrefixMappings();
  802. if (DEBUG)
  803. {
  804. System.out.println("ResultTreeHandler#flushPending - start flush: "
  805. + m_name);
  806. }
  807. flushElem();
  808. if (DEBUG)
  809. {
  810. System.out.println(
  811. "ResultTreeHandler#flushPending - after flush, isPending: "
  812. + m_elemIsPending);
  813. }
  814. m_nsContextPushed = false;
  815. }
  816. }
  817. /**
  818. * Given a result tree fragment, walk the tree and
  819. * output it to the result stream.
  820. *
  821. * @param obj Result tree fragment object
  822. * @param support XPath context for the result tree fragment
  823. *
  824. * @throws org.xml.sax.SAXException
  825. */
  826. public void outputResultTreeFragment(XObject obj, XPathContext support)
  827. throws org.xml.sax.SAXException
  828. {
  829. int doc = obj.rtf();
  830. DTM dtm = support.getDTM(doc);
  831. if(null != dtm)
  832. {
  833. for (int n = dtm.getFirstChild(doc); DTM.NULL != n;
  834. n = dtm.getNextSibling(n))
  835. {
  836. flushPending(true); // I think.
  837. startPrefixMapping("","");
  838. dtm.dispatchToEvents(n, this);
  839. }
  840. }
  841. }
  842. /**
  843. * To fullfill the FormatterListener interface... no action
  844. * for the moment.
  845. *
  846. * @param locator Document locator
  847. */
  848. public void setDocumentLocator(Locator locator){}
  849. /**
  850. * This function checks to make sure a given prefix is really
  851. * declared. It might not be, because it may be an excluded prefix.
  852. * If it's not, it still needs to be declared at this point.
  853. * TODO: This needs to be done at an earlier stage in the game... -sb
  854. *
  855. * @param ns Namespace URI of the element
  856. * @param rawName Raw name of element (with prefix)
  857. *
  858. * @throws org.xml.sax.SAXException
  859. */
  860. public void ensurePrefixIsDeclared(String ns, String rawName)
  861. throws org.xml.sax.SAXException
  862. {
  863. if (ns != null && ns.length() > 0)
  864. {
  865. int index;
  866. String prefix = (index = rawName.indexOf(":")) < 0
  867. ? "" : rawName.substring(0, index);
  868. if (null != prefix)
  869. {
  870. String foundURI = m_nsSupport.getURI(prefix);
  871. if ((null == foundURI) ||!foundURI.equals(ns))
  872. {
  873. startPrefixMapping(prefix, ns, false);
  874. // Bugzilla1133: Generate attribute as well as namespace event.
  875. // SAX does expect both.
  876. m_attributes.addAttribute("http://www.w3.org/2000/xmlns/",
  877. prefix,
  878. "xmlns"+(prefix.length()==0 ? "" : ":")+prefix,
  879. "CDATA", ns);
  880. }
  881. }
  882. }
  883. }
  884. /**
  885. * This function checks to make sure a given prefix is really
  886. * declared. It might not be, because it may be an excluded prefix.
  887. * If it's not, it still needs to be declared at this point.
  888. * TODO: This needs to be done at an earlier stage in the game... -sb
  889. *
  890. * @param ns Namespace URI of the element
  891. * @param rawName Raw name of element (with prefix)
  892. *
  893. * NEEDSDOC @param dtm
  894. * NEEDSDOC @param namespace
  895. *
  896. * @throws org.xml.sax.SAXException
  897. */
  898. public void ensureNamespaceDeclDeclared(DTM dtm, int namespace)
  899. throws org.xml.sax.SAXException
  900. {
  901. String uri = dtm.getNodeValue(namespace);
  902. String prefix = dtm.getNodeNameX(namespace);
  903. if ((uri != null && uri.length() > 0) && (null != prefix))
  904. {
  905. String foundURI = m_nsSupport.getURI(prefix);
  906. if ((null == foundURI) ||!foundURI.equals(uri))
  907. {
  908. startPrefixMapping(prefix, uri, false);
  909. }
  910. }
  911. }
  912. /**
  913. * Add the attributes that have been declared to the attribute list.
  914. * (Seems like I shouldn't have to do this...)
  915. * Internally deprecated in favor of combined startAndAddPrefixMappings();
  916. *
  917. *
  918. * @throws org.xml.sax.SAXException
  919. */
  920. protected void sendStartPrefixMappings() throws org.xml.sax.SAXException
  921. {
  922. Enumeration prefixes = m_nsSupport.getDeclaredPrefixes();
  923. ContentHandler handler = m_contentHandler;
  924. while (prefixes.hasMoreElements())
  925. {
  926. String prefix = (String) prefixes.nextElement();
  927. handler.startPrefixMapping(prefix, m_nsSupport.getURI(prefix));
  928. }
  929. }
  930. /**
  931. * Combination of sendStartPrefixMappings and
  932. * addNSDeclsToAttrs() (which it mostly replaces). Merging the two
  933. * loops is significantly more efficient.
  934. *
  935. * @throws org.xml.sax.SAXException */
  936. protected void startAndAddPrefixMappings() throws org.xml.sax.SAXException
  937. {
  938. Enumeration prefixes = m_nsSupport.getDeclaredPrefixes();
  939. ContentHandler handler = m_contentHandler;
  940. while (prefixes.hasMoreElements())
  941. {
  942. String prefix = (String) prefixes.nextElement();
  943. String uri=m_nsSupport.getURI(prefix);
  944. // Send event
  945. handler.startPrefixMapping(prefix, uri);
  946. // Set attribute
  947. boolean isDefault = (prefix.length() == 0);
  948. String name;
  949. if (isDefault)
  950. {
  951. //prefix = "xml";
  952. name = "xmlns";
  953. }
  954. else
  955. name = "xmlns:" + prefix;
  956. if (null == uri)
  957. uri = "";
  958. m_attributes.addAttribute("http://www.w3.org/2000/xmlns/",
  959. prefix, name, "CDATA", uri);
  960. }
  961. m_nsDeclsHaveBeenAdded=true;
  962. }
  963. /**
  964. * Add the attributes that have been declared to the attribute list.
  965. * (Seems like I shouldn't have to do this...)
  966. *
  967. * @throws org.xml.sax.SAXException
  968. */
  969. protected void sendEndPrefixMappings() throws org.xml.sax.SAXException
  970. {
  971. Enumeration prefixes = m_nsSupport.getDeclaredPrefixes();
  972. ContentHandler handler = m_contentHandler;
  973. while (prefixes.hasMoreElements())
  974. {
  975. String prefix = (String) prefixes.nextElement();
  976. handler.endPrefixMapping(prefix);
  977. }
  978. }
  979. /**
  980. * Check to see if we should switch serializers based on the
  981. * first output element being an HTML element.
  982. *
  983. * @param ns Namespace URI of the element
  984. * @param localName Local part of name of the element
  985. *
  986. * @throws org.xml.sax.SAXException
  987. */
  988. private void checkForSerializerSwitch(String ns, String localName)
  989. throws org.xml.sax.SAXException
  990. {
  991. try
  992. {
  993. if (m_docPending)
  994. {
  995. SerializerSwitcher.switchSerializerIfHTML(m_transformer, ns,
  996. localName);
  997. }
  998. }
  999. catch (TransformerException te)
  1000. {
  1001. throw new org.xml.sax.SAXException(te);
  1002. }
  1003. }
  1004. /**
  1005. * Add the attributes that have been declared to the attribute list.
  1006. *
  1007. * %REVIEW% This should have been done automatically during
  1008. * flushPending(boolean); is it ever explicitly reinvoked?
  1009. */
  1010. public void addNSDeclsToAttrs()
  1011. {
  1012. Enumeration prefixes = m_nsSupport.getDeclaredPrefixes();
  1013. while (prefixes.hasMoreElements())
  1014. {
  1015. String prefix = (String) prefixes.nextElement();
  1016. boolean isDefault = (prefix.length() == 0);
  1017. String name;
  1018. if (isDefault)
  1019. {
  1020. //prefix = "xml";
  1021. name = "xmlns";
  1022. }
  1023. else
  1024. name = "xmlns:" + prefix;
  1025. String uri = m_nsSupport.getURI(prefix);
  1026. if (null == uri)
  1027. uri = "";
  1028. m_attributes.addAttribute("http://www.w3.org/2000/xmlns/",
  1029. prefix, name, "CDATA", uri);
  1030. m_nsDeclsHaveBeenAdded = true;
  1031. }
  1032. }
  1033. /**
  1034. * Copy <KBD>xmlns:</KBD> attributes in if not already in scope.
  1035. *
  1036. * As a quick hack to support ClonerToResultTree, this can also be used
  1037. * to copy an individual namespace node.
  1038. *
  1039. * @param src Source Node
  1040. * NEEDSDOC @param type
  1041. * NEEDSDOC @param dtm
  1042. *
  1043. * @throws TransformerException
  1044. */
  1045. public void processNSDecls(int src, int type, DTM dtm)
  1046. throws TransformerException
  1047. {
  1048. try
  1049. {
  1050. if (type == DTM.ELEMENT_NODE)
  1051. {
  1052. for (int namespace = dtm.getFirstNamespaceNode(src, true);
  1053. DTM.NULL != namespace;
  1054. namespace = dtm.getNextNamespaceNode(src, namespace, true))
  1055. {
  1056. // String prefix = dtm.getPrefix(namespace);
  1057. String prefix = dtm.getNodeNameX(namespace);
  1058. String desturi = getURI(prefix);
  1059. String srcURI = dtm.getNodeValue(namespace);
  1060. if (!srcURI.equalsIgnoreCase(desturi))
  1061. {
  1062. this.startPrefixMapping(prefix, srcURI, false);
  1063. }
  1064. }
  1065. }
  1066. else if (type == DTM.NAMESPACE_NODE)
  1067. {
  1068. String prefix = dtm.getNodeNameX(src);
  1069. String desturi = getURI(prefix);
  1070. String srcURI = dtm.getNodeValue(src);
  1071. if (!srcURI.equalsIgnoreCase(desturi))
  1072. {
  1073. this.startPrefixMapping(prefix, srcURI, false);
  1074. }
  1075. }
  1076. }
  1077. catch (org.xml.sax.SAXException se)
  1078. {
  1079. throw new TransformerException(se);
  1080. }
  1081. }
  1082. /**
  1083. * Given a prefix, return the namespace,
  1084. *
  1085. * @param prefix Given prefix name
  1086. *
  1087. * @return Namespace associated with the given prefix, or null
  1088. */
  1089. public String getURI(String prefix)
  1090. {
  1091. return m_nsSupport.getURI(prefix);
  1092. }
  1093. /**
  1094. * Given a namespace, try and find a prefix.
  1095. *
  1096. * @param namespace Given namespace URI
  1097. *
  1098. * @return Prefix name associated with namespace URI
  1099. */
  1100. public String getPrefix(String namespace)
  1101. {
  1102. // This Enumeration business may be too slow for our purposes...
  1103. Enumeration enum = m_nsSupport.getPrefixes();
  1104. while (enum.hasMoreElements())
  1105. {
  1106. String prefix = (String) enum.nextElement();
  1107. if (m_nsSupport.getURI(prefix).equals(namespace))
  1108. return prefix;
  1109. }
  1110. return null;
  1111. }
  1112. /**
  1113. * Get the NamespaceSupport object.
  1114. *
  1115. * @return NamespaceSupport object.
  1116. */
  1117. public NamespaceSupport getNamespaceSupport()
  1118. {
  1119. return m_nsSupport;
  1120. }
  1121. // /**
  1122. // * Override QueuedEvents#initQSE.
  1123. // *
  1124. // * @param qse Give queued Sax event
  1125. // */
  1126. // protected void initQSE(QueuedSAXEvent qse)
  1127. // {
  1128. //
  1129. // // qse.setContentHandler(m_contentHandler);
  1130. // // qse.setTransformer(m_transformer);
  1131. // // qse.setTraceManager(m_tracer);
  1132. // }
  1133. /**
  1134. * Return the current content handler.
  1135. *
  1136. * @return The current content handler, or null if none
  1137. * has been registered.
  1138. * @see #setContentHandler
  1139. */
  1140. public final ContentHandler getContentHandler()
  1141. {
  1142. return m_contentHandler;
  1143. }
  1144. /**
  1145. * Set the current content handler.
  1146. *
  1147. *
  1148. * @param ch Content Handler to be set
  1149. * @return The current content handler, or null if none
  1150. * has been registered.
  1151. * @see #getContentHandler
  1152. */
  1153. public void setContentHandler(ContentHandler ch)
  1154. {
  1155. m_contentHandler = ch;
  1156. m_isTransformClient = (m_contentHandler instanceof TransformerClient);
  1157. if (m_contentHandler instanceof LexicalHandler)
  1158. m_lexicalHandler = (LexicalHandler) m_contentHandler;
  1159. else
  1160. m_lexicalHandler = null;
  1161. reInitEvents();
  1162. }
  1163. /**
  1164. * Get a unique namespace value.
  1165. *
  1166. * @return a unique namespace value to be used with a
  1167. * fabricated prefix
  1168. */
  1169. public int getUniqueNSValue()
  1170. {
  1171. return m_uniqueNSValue++;
  1172. }
  1173. /**
  1174. * Get new unique namespace prefix.
  1175. *
  1176. * @return Unique fabricated prefix.
  1177. */
  1178. public String getNewUniqueNSPrefix()
  1179. {
  1180. return S_NAMESPACEPREFIX + String.valueOf(getUniqueNSValue());
  1181. }
  1182. /**
  1183. * Get the pending attributes. We have to delay the call to
  1184. * m_flistener.startElement(name, atts) because of the
  1185. * xsl:attribute and xsl:copy calls. In other words,
  1186. * the attributes have to be fully collected before you
  1187. * can call startElement.
  1188. *
  1189. * @return the pending attributes.
  1190. */
  1191. public MutableAttrListImpl getPendingAttributes()
  1192. {
  1193. return m_attributes;
  1194. }
  1195. /**
  1196. * Add an attribute to the end of the list.
  1197. *
  1198. * <p>Do not pass in xmlns decls to this function!
  1199. *
  1200. * <p>For the sake of speed, this method does no checking
  1201. * to see if the attribute is already in the list: that is
  1202. * the responsibility of the application.</p>
  1203. *
  1204. * @param uri The Namespace URI, or the empty string if
  1205. * none is available or Namespace processing is not
  1206. * being performed.
  1207. * @param localName The local name, or the empty string if
  1208. * Namespace processing is not being performed.
  1209. * @param rawName The raw XML 1.0 name, or the empty string
  1210. * if raw names are not available.
  1211. * @param type The attribute type as a string.
  1212. * @param value The attribute value.
  1213. *
  1214. * @throws TransformerException
  1215. */
  1216. public void addAttribute(
  1217. String uri, String localName, String rawName, String type, String value)
  1218. throws TransformerException
  1219. {
  1220. // %REVIEW% See Bugzilla 4344. Do we need an "else" that announces
  1221. // an error? Technically, this can't happen unless the stylesheet
  1222. // is unreasonable... but it's unclear whether silent or noisy
  1223. // failure is called for.
  1224. // Will add an "else" and emit a warning message. This should
  1225. // cover testcases such as copyerr04-07, attribset19,34,35,
  1226. // attribseterr08...(is)
  1227. if (m_elemIsPending)
  1228. {
  1229. // %REVIEW% %OPT% Is this ever needed?????
  1230. // The check is not needed. See Bugzilla 10306.
  1231. // if (!m_nsDeclsHaveBeenAdded)
  1232. addNSDeclsToAttrs();
  1233. if (null == uri) { // defensive, should not really need this.
  1234. uri = "";
  1235. }
  1236. try {
  1237. if (!rawName.equals("xmlns")) { // don't handle xmlns default namespace.
  1238. ensurePrefixIsDeclared(uri, rawName);
  1239. }
  1240. } catch (org.xml.sax.SAXException se) {
  1241. throw new TransformerException(se);
  1242. }
  1243. if (DEBUG) {
  1244. System.out.println("ResultTreeHandler#addAttribute Adding attr: "
  1245. + localName + ", " + uri);
  1246. }
  1247. if (!isDefinedNSDecl(rawName, value)) {
  1248. m_attributes.addAttribute(uri, localName, rawName, type, value);
  1249. }
  1250. } else {
  1251. m_transformer.getMsgMgr().warn(m_stylesheetRoot,
  1252. XSLTErrorResources.WG_ILLEGAL_ATTRIBUTE_POSITION,
  1253. new Object[]{ localName });
  1254. }
  1255. }
  1256. /**
  1257. * Return whether or not a namespace declaration is defined
  1258. *
  1259. *
  1260. * @param rawName Raw name of namespace element
  1261. * @param value URI of given namespace
  1262. *
  1263. * @return True if the namespace is already defined in list of
  1264. * namespaces
  1265. */
  1266. public boolean isDefinedNSDecl(String rawName, String value)
  1267. {
  1268. if (rawName.equals("xmlns") || rawName.startsWith("xmlns:"))
  1269. {
  1270. int index;
  1271. String prefix = (index = rawName.indexOf(":")) < 0
  1272. ? "" : rawName.substring(0, index);
  1273. String definedURI = m_nsSupport.getURI(prefix);
  1274. if (null != definedURI)
  1275. {
  1276. if (definedURI.equals(value))
  1277. {
  1278. return true;
  1279. }
  1280. else
  1281. return false;
  1282. }
  1283. else
  1284. return false;
  1285. }
  1286. else
  1287. return false;
  1288. }
  1289. /**
  1290. * Returns whether a namespace is defined
  1291. *
  1292. *
  1293. * @param attr Namespace attribute node
  1294. *
  1295. * @return True if the namespace is already defined in
  1296. * list of namespaces
  1297. */
  1298. public boolean isDefinedNSDecl(int attr)
  1299. {
  1300. DTM dtm = m_transformer.getXPathContext().getDTM(attr);
  1301. if (DTM.NAMESPACE_NODE == dtm.getNodeType(attr))
  1302. {
  1303. // String prefix = dtm.getPrefix(attr);
  1304. String prefix = dtm.getNodeNameX(attr);
  1305. String uri = getURI(prefix);
  1306. if ((null != uri) && uri.equals(dtm.getStringValue(attr)))
  1307. return true;
  1308. }
  1309. return false;
  1310. }
  1311. /**
  1312. * Returns whether a namespace is defined
  1313. *
  1314. *
  1315. * @param attr Namespace attribute node
  1316. * @param dtm The DTM that owns attr.
  1317. *
  1318. * @return True if the namespace is already defined in
  1319. * list of namespaces
  1320. */
  1321. public boolean isDefinedNSDecl(int attr, DTM dtm)
  1322. {
  1323. if (DTM.NAMESPACE_NODE == dtm.getNodeType(attr))
  1324. {
  1325. // String prefix = dtm.getPrefix(attr);
  1326. String prefix = dtm.getNodeNameX(attr);
  1327. String uri = getURI(prefix);
  1328. if ((null != uri) && uri.equals(dtm.getStringValue(attr)))
  1329. return true;
  1330. }
  1331. return false;
  1332. }
  1333. /**
  1334. * Copy an DOM attribute to the created output element, executing
  1335. * attribute templates as need be, and processing the xsl:use
  1336. * attribute.
  1337. *
  1338. * @param attr Attribute node to add to result tree
  1339. *
  1340. * @throws TransformerException
  1341. */
  1342. public void addAttribute(int attr) throws TransformerException
  1343. {
  1344. DTM dtm = m_transformer.getXPathContext().getDTM(attr);
  1345. if (isDefinedNSDecl(attr, dtm))
  1346. return;
  1347. String ns = dtm.getNamespaceURI(attr);
  1348. if (ns == null)
  1349. ns = "";
  1350. // %OPT% ...can I just store the node handle?
  1351. addAttribute(ns, dtm.getLocalName(attr), dtm.getNodeName(attr), "CDATA",
  1352. dtm.getNodeValue(attr));
  1353. } // end copyAttributeToTarget method
  1354. /**
  1355. * Copy DOM attributes to the result element.
  1356. *
  1357. * @param src Source node with the attributes
  1358. *
  1359. * @throws TransformerException
  1360. */
  1361. public void addAttributes(int src) throws TransformerException
  1362. {
  1363. DTM dtm = m_transformer.getXPathContext().getDTM(src);
  1364. for (int node = dtm.getFirstAttribute(src); DTM.NULL != node;
  1365. node = dtm.getNextAttribute(node))
  1366. {
  1367. addAttribute(node);
  1368. }
  1369. }
  1370. /**
  1371. * Tell if an element is pending, to be output to the result tree.
  1372. *
  1373. * @return True if an element is pending
  1374. */
  1375. public final boolean isElementPending()
  1376. {
  1377. return m_elemIsPending;
  1378. }
  1379. /**
  1380. * Retrieves the stylesheet element that produced
  1381. * the SAX event.
  1382. *
  1383. * <p>Please note that the ElemTemplateElement returned may
  1384. * be in a default template, and thus may not be
  1385. * defined in the stylesheet.</p>
  1386. *
  1387. * @return the stylesheet element that produced the SAX event.
  1388. */
  1389. public ElemTemplateElement getCurrentElement()
  1390. {
  1391. if (m_elemIsPending)
  1392. return m_snapshot.m_currentElement;
  1393. else
  1394. return m_transformer.getCurrentElement();
  1395. }
  1396. /**
  1397. * This method retrieves the current context node
  1398. * in the source tree.
  1399. *
  1400. * @return the current context node in the source tree.
  1401. */
  1402. public org.w3c.dom.Node getCurrentNode()
  1403. {
  1404. if (m_snapshot.m_currentNode != null)
  1405. {
  1406. return m_snapshot.m_currentNode;
  1407. }
  1408. else
  1409. {
  1410. DTM dtm = m_transformer.getXPathContext().getDTM(m_transformer.getCurrentNode());
  1411. return dtm.getNode(m_transformer.getCurrentNode());
  1412. }
  1413. }
  1414. /**
  1415. * This method retrieves the xsl:template
  1416. * that is in effect, which may be a matched template
  1417. * or a named template.
  1418. *
  1419. * <p>Please note that the ElemTemplate returned may
  1420. * be a default template, and thus may not have a template
  1421. * defined in the stylesheet.</p>
  1422. *
  1423. * @return the xsl:template that is in effect
  1424. */
  1425. public ElemTemplate getCurrentTemplate()
  1426. {
  1427. if (m_elemIsPending)
  1428. return m_snapshot.m_currentTemplate;
  1429. else
  1430. return m_transformer.getCurrentTemplate();
  1431. }
  1432. /**
  1433. * This method retrieves the xsl:template
  1434. * that was matched. Note that this may not be
  1435. * the same thing as the current template (which
  1436. * may be from getCurrentElement()), since a named
  1437. * template may be in effect.
  1438. *
  1439. * <p>Please note that the ElemTemplate returned may
  1440. * be a default template, and thus may not have a template
  1441. * defined in the stylesheet.</p>
  1442. *
  1443. * @return the xsl:template that was matched.
  1444. */
  1445. public ElemTemplate getMatchedTemplate()
  1446. {
  1447. if (m_elemIsPending)
  1448. return m_snapshot.m_matchedTemplate;
  1449. else
  1450. return m_transformer.getMatchedTemplate();
  1451. }
  1452. /**
  1453. * Retrieves the node in the source tree that matched
  1454. * the template obtained via getMatchedTemplate().
  1455. *
  1456. * @return the node in the source tree that matched
  1457. * the template obtained via getMatchedTemplate().
  1458. */
  1459. public org.w3c.dom.Node getMatchedNode()
  1460. {
  1461. if (m_elemIsPending)
  1462. {
  1463. DTM dtm = m_transformer.getXPathContext().getDTM(m_snapshot.m_matchedNode);
  1464. return dtm.getNode(m_snapshot.m_matchedNode);
  1465. }
  1466. else
  1467. {
  1468. DTM dtm = m_transformer.getXPathContext().getDTM(m_transformer.getMatchedNode());
  1469. return dtm.getNode(m_transformer.getMatchedNode());
  1470. }
  1471. }
  1472. /**
  1473. * Get the current context node list.
  1474. *
  1475. * @return the current context node list.
  1476. */
  1477. public org.w3c.dom.traversal.NodeIterator getContextNodeList()
  1478. {
  1479. if (m_elemIsPending)
  1480. {
  1481. return new org.apache.xml.dtm.ref.DTMNodeIterator(m_snapshot.m_contextNodeList);
  1482. }
  1483. else
  1484. return new org.apache.xml.dtm.ref.DTMNodeIterator(m_transformer.getContextNodeList());
  1485. }
  1486. /**
  1487. * Get the TrAX Transformer object in effect.
  1488. *
  1489. * @return the TrAX Transformer object in effect.
  1490. */
  1491. public Transformer getTransformer()
  1492. {
  1493. return m_transformer;
  1494. }
  1495. // Implement ErrorHandler
  1496. /**
  1497. * Receive notification of a warning.
  1498. *
  1499. * <p>SAX parsers will use this method to report conditions that
  1500. * are not errors or fatal errors as defined by the XML 1.0
  1501. * recommendation. The default behaviour is to take no action.</p>
  1502. *
  1503. * <p>The SAX parser must continue to provide normal parsing events
  1504. * after invoking this method: it should still be possible for the
  1505. * application to process the document through to the end.</p>
  1506. *
  1507. * <p>Filters may use this method to report other, non-XML warnings
  1508. * as well.</p>
  1509. *
  1510. * @param exception The warning information encapsulated in a
  1511. * SAX parse exception.
  1512. * @exception org.xml.sax.SAXException Any SAX exception, possibly
  1513. * wrapping another exception.
  1514. * @see org.xml.sax.SAXParseException
  1515. */
  1516. public void warning (SAXParseException exception)
  1517. throws SAXException
  1518. {
  1519. if (m_contentHandler instanceof ErrorHandler)
  1520. ((ErrorHandler)m_contentHandler).warning(exception);
  1521. }
  1522. /**
  1523. * Receive notification of a recoverable error.
  1524. *
  1525. * <p>This corresponds to the definition of "error" in section 1.2
  1526. * of the W3C XML 1.0 Recommendation. For example, a validating
  1527. * parser would use this callback to report the violation of a
  1528. * validity constraint. The default behaviour is to take no
  1529. * action.</p>
  1530. *
  1531. * <p>The SAX parser must continue to provide normal parsing events
  1532. * after invoking this method: it should still be possible for the
  1533. * application to process the document through to the end. If the
  1534. * application cannot do so, then the parser should report a fatal
  1535. * error even if the XML 1.0 recommendation does not require it to
  1536. * do so.</p>
  1537. *
  1538. * <p>Filters may use this method to report other, non-XML errors
  1539. * as well.</p>
  1540. *
  1541. * @param exception The error information encapsulated in a
  1542. * SAX parse exception.
  1543. * @exception org.xml.sax.SAXException Any SAX exception, possibly
  1544. * wrapping another exception.
  1545. * @see org.xml.sax.SAXParseException
  1546. */
  1547. public void error (SAXParseException exception)
  1548. throws SAXException
  1549. {
  1550. if (m_contentHandler instanceof ErrorHandler)
  1551. ((ErrorHandler)m_contentHandler).error(exception);
  1552. }
  1553. /**
  1554. * Receive notification of a non-recoverable error.
  1555. *
  1556. * <p>This corresponds to the definition of "fatal error" in
  1557. * section 1.2 of the W3C XML 1.0 Recommendation. For example, a
  1558. * parser would use this callback to report the violation of a
  1559. * well-formedness constraint.</p>
  1560. *
  1561. * <p>The application must assume that the document is unusable
  1562. * after the parser has invoked this method, and should continue
  1563. * (if at all) only for the sake of collecting addition error
  1564. * messages: in fact, SAX parsers are free to stop reporting any
  1565. * other events once this method has been invoked.</p>
  1566. *
  1567. * @param exception The error information encapsulated in a
  1568. * SAX parse exception.
  1569. * @exception org.xml.sax.SAXException Any SAX exception, possibly
  1570. * wrapping another exception.
  1571. * @see org.xml.sax.SAXParseException
  1572. */
  1573. public void fatalError (SAXParseException exception)
  1574. throws SAXException
  1575. {
  1576. m_elemIsPending = false;
  1577. m_docEnded = true;
  1578. m_docPending = false;
  1579. if (m_contentHandler instanceof ErrorHandler)
  1580. ((ErrorHandler)m_contentHandler).fatalError(exception);
  1581. }
  1582. boolean m_isTransformClient = false;
  1583. /**
  1584. * Use the SAX2 helper class to track result namespaces.
  1585. */
  1586. NamespaceSupport m_nsSupport = new NamespaceSupport2();
  1587. /**
  1588. * The transformer object.
  1589. */
  1590. private TransformerImpl m_transformer;
  1591. /**
  1592. * The content handler. May be null, in which
  1593. * case, we'll defer to the content handler in the
  1594. * transformer.
  1595. */
  1596. private ContentHandler m_contentHandler;
  1597. /** The LexicalHandler */
  1598. private LexicalHandler m_lexicalHandler;
  1599. /**
  1600. * The root of a linked set of stylesheets.
  1601. */
  1602. private StylesheetRoot m_stylesheetRoot = null;
  1603. /**
  1604. * This is used whenever a unique namespace is needed.
  1605. */
  1606. private int m_uniqueNSValue = 0;
  1607. /** Prefix used to create unique prefix names */
  1608. private static final String S_NAMESPACEPREFIX = "ns";
  1609. /**
  1610. * This class clones nodes to the result tree.
  1611. */
  1612. public ClonerToResultTree m_cloner;
  1613. /**
  1614. * Trace manager for debug support.
  1615. */
  1616. private TraceManager m_tracer;
  1617. private QueuedStateSnapshot m_snapshot = new QueuedStateSnapshot();
  1618. // These are passed to flushPending, to help it decide if it
  1619. // should really flush.
  1620. class QueuedStateSnapshot
  1621. {
  1622. /**
  1623. * The stylesheet element that produced the SAX event.
  1624. */
  1625. ElemTemplateElement m_currentElement;
  1626. /**
  1627. * The current context node in the source tree.
  1628. */
  1629. org.w3c.dom.Node m_currentNode;
  1630. /**
  1631. * The xsl:template that is in effect, which may be a matched template
  1632. * or a named template.
  1633. */
  1634. ElemTemplate m_currentTemplate;
  1635. /**
  1636. * The xsl:template that was matched.
  1637. */
  1638. ElemTemplate m_matchedTemplate;
  1639. /**
  1640. * The node in the source tree that matched
  1641. * the template obtained via getMatchedTemplate().
  1642. */
  1643. int m_matchedNode;
  1644. /**
  1645. * The current context node list.
  1646. */
  1647. DTMIterator m_contextNodeList;
  1648. }
  1649. }