KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xalan > templates > ElemTemplateElement


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: ElemTemplateElement.java,v 1.65 2004/02/24 03:55:47 zongaro Exp $
18  */

19 package org.apache.xalan.templates;
20
21 import java.io.Serializable JavaDoc;
22 import java.util.Enumeration JavaDoc;
23 import java.util.Vector JavaDoc;
24
25 import javax.xml.transform.SourceLocator JavaDoc;
26 import javax.xml.transform.TransformerException JavaDoc;
27
28 import org.apache.xalan.res.XSLMessages;
29 import org.apache.xalan.res.XSLTErrorResources;
30 import org.apache.xalan.transformer.TransformerImpl;
31 import org.apache.xml.serializer.SerializationHandler;
32 import org.apache.xml.utils.PrefixResolver;
33 import org.apache.xml.utils.UnImplNode;
34 import org.apache.xpath.ExpressionNode;
35 import org.apache.xpath.WhitespaceStrippingElementMatcher;
36
37 import org.w3c.dom.DOMException JavaDoc;
38 import org.w3c.dom.Document JavaDoc;
39 import org.w3c.dom.Node JavaDoc;
40 import org.w3c.dom.NodeList JavaDoc;
41
42 import org.xml.sax.helpers.NamespaceSupport JavaDoc;
43
44 /**
45  * An instance of this class represents an element inside
46  * an xsl:template class. It has a single "execute" method
47  * which is expected to perform the given action on the
48  * result tree.
49  * This class acts like a Element node, and implements the
50  * Element interface, but is not a full implementation
51  * of that interface... it only implements enough for
52  * basic traversal of the tree.
53  *
54  * @see Stylesheet
55  * @xsl.usage advanced
56  */

57 public class ElemTemplateElement extends UnImplNode
58         implements PrefixResolver, Serializable JavaDoc, ExpressionNode,
59                    WhitespaceStrippingElementMatcher, XSLTVisitable
60 {
61
62   /**
63    * Construct a template element instance.
64    *
65    * @param transformer The XSLT TransformerFactory.
66    * @param stylesheetTree The owning stylesheet.
67    * @param name The name of the element.
68    * @param atts The element attributes.
69    * @param lineNumber The line in the XSLT file that the element occurs on.
70    * @param columnNumber The column index in the XSLT file that the element occurs on.
71    */

72   public ElemTemplateElement(){}
73
74   /**
75    * Tell if this template is a compiled template.
76    *
77    * @return Boolean flag indicating whether this is a compiled template
78    */

79   public boolean isCompiledTemplate()
80   {
81     return false;
82   }
83
84   /**
85    * Get an integer representation of the element type.
86    *
87    * @return An integer representation of the element, defined in the
88    * Constants class.
89    * @see org.apache.xalan.templates.Constants
90    */

91   public int getXSLToken()
92   {
93     return Constants.ELEMNAME_UNDEFINED;
94   }
95
96   /**
97    * Return the node name.
98    *
99    * @return An invalid node name
100    */

101   public String JavaDoc getNodeName()
102   {
103     return "Unknown XSLT Element";
104   }
105   
106   /**
107    * For now, just return the result of getNodeName(), which
108    * the local name.
109    *
110    * @return The result of getNodeName().
111    */

112   public String JavaDoc getLocalName()
113   {
114
115     return getNodeName();
116   }
117
118
119   /**
120    * This function will be called on top-level elements
121    * only, just before the transform begins.
122    *
123    * @param transformer The XSLT TransformerFactory.
124    *
125    * @throws TransformerException
126    */

127   public void runtimeInit(TransformerImpl transformer) throws TransformerException JavaDoc{}
128
129   /**
130    * Execute the element's primary function. Subclasses of this
131    * function may recursivly execute down the element tree.
132    *
133    * @param transformer The XSLT TransformerFactory.
134    * @param sourceNode The current context node.
135    * @param mode The current mode.
136    *
137    * @throws TransformerException if any checked exception occurs.
138    */

139   public void execute(
140           TransformerImpl transformer)
141             throws TransformerException JavaDoc{}
142
143   /**
144    * Get the owning "composed" stylesheet. This looks up the
145    * inheritance chain until it calls getStylesheetComposed
146    * on a Stylesheet object, which will Get the owning
147    * aggregated stylesheet, or that stylesheet if it is aggregated.
148    *
149    * @return the owning "composed" stylesheet.
150    */

151   public StylesheetComposed getStylesheetComposed()
152   {
153     return m_parentNode.getStylesheetComposed();
154   }
155
156   /**
157    * Get the owning stylesheet. This looks up the
158    * inheritance chain until it calls getStylesheet
159    * on a Stylesheet object, which will return itself.
160    *
161    * @return the owning stylesheet
162    */

163   public Stylesheet getStylesheet()
164   {
165     return (null==m_parentNode) ? null : m_parentNode.getStylesheet();
166   }
167
168   /**
169    * Get the owning root stylesheet. This looks up the
170    * inheritance chain until it calls StylesheetRoot
171    * on a Stylesheet object, which will return a reference
172    * to the root stylesheet.
173    *
174    * @return the owning root stylesheet
175    */

176   public StylesheetRoot getStylesheetRoot()
177   {
178     return m_parentNode.getStylesheetRoot();
179   }
180
181   /**
182    * This function is called during recomposition to
183    * control how this element is composed.
184    */

185   public void recompose(StylesheetRoot root) throws TransformerException JavaDoc
186   {
187   }
188
189   /**
190    * This function is called after everything else has been
191    * recomposed, and allows the template to set remaining
192    * values that may be based on some other property that
193    * depends on recomposition.
194    */

195   public void compose(StylesheetRoot sroot) throws TransformerException JavaDoc
196   {
197     resolvePrefixTables();
198     ElemTemplateElement t = getFirstChildElem();
199     m_hasTextLitOnly = ((t != null)
200               && (t.getXSLToken() == Constants.ELEMNAME_TEXTLITERALRESULT)
201               && (t.getNextSiblingElem() == null));
202               
203     StylesheetRoot.ComposeState cstate = sroot.getComposeState();
204     cstate.pushStackMark();
205   }
206   
207   /**
208    * This after the template's children have been composed.
209    */

210   public void endCompose(StylesheetRoot sroot) throws TransformerException JavaDoc
211   {
212     StylesheetRoot.ComposeState cstate = sroot.getComposeState();
213     cstate.popStackMark();
214   }
215
216   /**
217    * Throw a template element runtime error. (Note: should we throw a TransformerException instead?)
218    *
219    * @param msg key of the error that occured.
220    * @param args Arguments to be used in the message
221    */

222   public void error(String JavaDoc msg, Object JavaDoc[] args)
223   {
224
225     String JavaDoc themsg = XSLMessages.createMessage(msg, args);
226
227     throw new RuntimeException JavaDoc(XSLMessages.createMessage(
228                                     XSLTErrorResources.ER_ELEMTEMPLATEELEM_ERR,
229                                     new Object JavaDoc[]{ themsg }));
230   }
231   
232   /*
233    * Throw an error.
234    *
235    * @param msg Message key for the error
236    *
237    */

238   public void error(String JavaDoc msg)
239   {
240     error(msg, null);
241   }
242   
243
244   // Implemented DOM Element methods.
245
/**
246    * Add a child to the child list.
247    * NOTE: This presumes the child did not previously have a parent.
248    * Making that assumption makes this a less expensive operation -- but
249    * requires that if you *do* want to reparent a node, you use removeChild()
250    * first to remove it from its previous context. Failing to do so will
251    * damage the tree.
252    *
253    * @param newChild Child to be added to child list
254    *
255    * @return Child just added to the child list
256    * @throws DOMException
257    */

258   public Node appendChild(Node newChild) throws DOMException JavaDoc
259   {
260
261     if (null == newChild)
262     {
263       error(XSLTErrorResources.ER_NULL_CHILD, null); //"Trying to add a null child!");
264
}
265
266     ElemTemplateElement elem = (ElemTemplateElement) newChild;
267
268     if (null == m_firstChild)
269     {
270       m_firstChild = elem;
271     }
272     else
273     {
274       ElemTemplateElement last = (ElemTemplateElement) getLastChild();
275
276       last.m_nextSibling = elem;
277     }
278
279     elem.m_parentNode = this;
280
281     return newChild;
282   }
283
284   /**
285    * Add a child to the child list.
286    * NOTE: This presumes the child did not previously have a parent.
287    * Making that assumption makes this a less expensive operation -- but
288    * requires that if you *do* want to reparent a node, you use removeChild()
289    * first to remove it from its previous context. Failing to do so will
290    * damage the tree.
291    *
292    * @param newChild Child to be added to child list
293    *
294    * @return Child just added to the child list
295    */

296   public ElemTemplateElement appendChild(ElemTemplateElement elem)
297   {
298
299     if (null == elem)
300     {
301       error(XSLTErrorResources.ER_NULL_CHILD, null); //"Trying to add a null child!");
302
}
303
304     if (null == m_firstChild)
305     {
306       m_firstChild = elem;
307     }
308     else
309     {
310       ElemTemplateElement last = getLastChildElem();
311
312       last.m_nextSibling = elem;
313     }
314
315     elem.setParentElem(this);
316
317     return elem;
318   }
319
320
321   /**
322    * Tell if there are child nodes.
323    *
324    * @return True if there are child nodes
325    */

326   public boolean hasChildNodes()
327   {
328     return (null != m_firstChild);
329   }
330
331   /**
332    * Get the type of the node.
333    *
334    * @return Constant for this node type
335    */

336   public short getNodeType()
337   {
338     return org.w3c.dom.Node.ELEMENT_NODE;
339   }
340
341   /**
342    * Return the nodelist (same reference).
343    *
344    * @return The nodelist containing the child nodes (this)
345    */

346   public NodeList JavaDoc getChildNodes()
347   {
348     return this;
349   }
350
351   /**
352    * Remove a child.
353    * ADDED 9/8/200 to support compilation.
354    * TODO: ***** Alternative is "removeMe() from my parent if any"
355    * ... which is less well checked, but more convenient in some cases.
356    * Given that we assume only experts are calling this class, it might
357    * be preferable. It's less DOMish, though.
358    *
359    * @param childETE The child to remove. This operation is a no-op
360    * if oldChild is not a child of this node.
361    *
362    * @return the removed child, or null if the specified
363    * node was not a child of this element.
364    */

365   public ElemTemplateElement removeChild(ElemTemplateElement childETE)
366   {
367
368     if (childETE == null || childETE.m_parentNode != this)
369       return null;
370
371     // Pointers to the child
372
if (childETE == m_firstChild)
373       m_firstChild = childETE.m_nextSibling;
374     else
375     {
376       ElemTemplateElement prev = childETE.getPreviousSiblingElem();
377
378       prev.m_nextSibling = childETE.m_nextSibling;
379     }
380
381     // Pointers from the child
382
childETE.m_parentNode = null;
383     childETE.m_nextSibling = null;
384
385     return childETE;
386   }
387
388   /**
389    * Replace the old child with a new child.
390    *
391    * @param newChild New child to replace with
392    * @param oldChild Old child to be replaced
393    *
394    * @return The new child
395    *
396    * @throws DOMException
397    */

398   public Node replaceChild(Node newChild, Node oldChild) throws DOMException JavaDoc
399   {
400
401     if (oldChild == null || oldChild.getParentNode() != this)
402       return null;
403
404     ElemTemplateElement newChildElem = ((ElemTemplateElement) newChild);
405     ElemTemplateElement oldChildElem = ((ElemTemplateElement) oldChild);
406
407     // Fix up previous sibling.
408
ElemTemplateElement prev =
409       (ElemTemplateElement) oldChildElem.getPreviousSibling();
410
411     if (null != prev)
412       prev.m_nextSibling = newChildElem;
413
414     // Fix up parent (this)
415
if (m_firstChild == oldChildElem)
416       m_firstChild = newChildElem;
417
418     newChildElem.m_parentNode = this;
419     oldChildElem.m_parentNode = null;
420     newChildElem.m_nextSibling = oldChildElem.m_nextSibling;
421     oldChildElem.m_nextSibling = null;
422
423     // newChildElem.m_stylesheet = oldChildElem.m_stylesheet;
424
// oldChildElem.m_stylesheet = null;
425
return newChildElem;
426   }
427   
428   /**
429    * Unimplemented. See org.w3c.dom.Node
430    *
431    * @param newChild New child node to insert
432    * @param refChild Insert in front of this child
433    *
434    * @return null
435    *
436    * @throws DOMException
437    */

438   public Node insertBefore(Node newChild, Node refChild) throws DOMException JavaDoc
439   {
440     if(null == refChild)
441     {
442         appendChild(newChild);
443         return newChild;
444     }
445     
446     if(newChild == refChild)
447     {
448         // hmm...
449
return newChild;
450     }
451
452     Node node = m_firstChild;
453     Node prev = null;
454     boolean foundit = false;
455     
456     while (null != node)
457     {
458         // If the newChild is already in the tree, it is first removed.
459
if(newChild == node)
460         {
461             if(null != prev)
462                 ((ElemTemplateElement)prev).m_nextSibling =
463                     (ElemTemplateElement)node.getNextSibling();
464             else
465                 m_firstChild = (ElemTemplateElement)node.getNextSibling();
466             node = node.getNextSibling();
467             continue; // prev remains the same.
468
}
469         if(refChild == node)
470         {
471             if(null != prev)
472             {
473                 ((ElemTemplateElement)prev).m_nextSibling = (ElemTemplateElement)newChild;
474             }
475             else
476             {
477                 m_firstChild = (ElemTemplateElement)newChild;
478             }
479             ((ElemTemplateElement)newChild).m_nextSibling = (ElemTemplateElement)refChild;
480             ((ElemTemplateElement)newChild).setParentElem(this);
481             prev = newChild;
482             node = node.getNextSibling();
483             foundit = true;
484             continue;
485         }
486         prev = node;
487         node = node.getNextSibling();
488     }
489     
490     if(!foundit)
491         throw new DOMException JavaDoc(DOMException.NOT_FOUND_ERR,
492             "refChild was not found in insertBefore method!");
493     else
494         return newChild;
495   }
496
497
498   /**
499    * Replace the old child with a new child.
500    *
501    * @param newChild New child to replace with
502    * @param oldChild Old child to be replaced
503    *
504    * @return The new child
505    *
506    * @throws DOMException
507    */

508   public ElemTemplateElement replaceChild(ElemTemplateElement newChildElem,
509                                           ElemTemplateElement oldChildElem)
510   {
511
512     if (oldChildElem == null || oldChildElem.getParentElem() != this)
513       return null;
514
515     // Fix up previous sibling.
516
ElemTemplateElement prev =
517       oldChildElem.getPreviousSiblingElem();
518
519     if (null != prev)
520       prev.m_nextSibling = newChildElem;
521
522     // Fix up parent (this)
523
if (m_firstChild == oldChildElem)
524       m_firstChild = newChildElem;
525
526     newChildElem.m_parentNode = this;
527     oldChildElem.m_parentNode = null;
528     newChildElem.m_nextSibling = oldChildElem.m_nextSibling;
529     oldChildElem.m_nextSibling = null;
530
531     // newChildElem.m_stylesheet = oldChildElem.m_stylesheet;
532
// oldChildElem.m_stylesheet = null;
533
return newChildElem;
534   }
535
536   /**
537    * NodeList method: Count the immediate children of this node
538    *
539    * @return The count of children of this node
540    */

541   public int getLength()
542   {
543
544     // It is assumed that the getChildNodes call synchronized
545
// the children. Therefore, we can access the first child
546
// reference directly.
547
int count = 0;
548
549     for (ElemTemplateElement node = m_firstChild; node != null;
550             node = node.m_nextSibling)
551     {
552       count++;
553     }
554
555     return count;
556   } // getLength():int
557

558   /**
559    * NodeList method: Return the Nth immediate child of this node, or
560    * null if the index is out of bounds.
561    *
562    * @param index Index of child to find
563    * @return org.w3c.dom.Node: the child node at given index
564    */

565   public Node item(int index)
566   {
567
568     // It is assumed that the getChildNodes call synchronized
569
// the children. Therefore, we can access the first child
570
// reference directly.
571
ElemTemplateElement node = m_firstChild;
572
573     for (int i = 0; i < index && node != null; i++)
574     {
575       node = node.m_nextSibling;
576     }
577
578     return node;
579   } // item(int):Node
580

581   /**
582    * Get the stylesheet owner.
583    *
584    * @return The stylesheet owner
585    */

586   public Document JavaDoc getOwnerDocument()
587   {
588     return getStylesheet();
589   }
590   
591   /**
592    * Get the owning xsl:template element.
593    *
594    * @return The owning xsl:template element, this element if it is a xsl:template, or null if not found.
595    */

596   public ElemTemplate getOwnerXSLTemplate()
597   {
598     ElemTemplateElement el = this;
599     int type = el.getXSLToken();
600     while((null != el) && (type != Constants.ELEMNAME_TEMPLATE))
601     {
602         el = el.getParentElem();
603         if(null != el)
604             type = el.getXSLToken();
605     }
606     return (ElemTemplate)el;
607   }
608
609
610   /**
611    * Return the element name.
612    *
613    * @return The element name
614    */

615   public String JavaDoc getTagName()
616   {
617     return getNodeName();
618   }
619   
620   /**
621    * Tell if this element only has one text child, for optimization purposes.
622    * @return true of this element only has one text literal child.
623    */

624   public boolean hasTextLitOnly()
625   {
626     return m_hasTextLitOnly;
627   }
628
629   /**
630    * Return the base identifier.
631    *
632    * @return The base identifier
633    */

634   public String JavaDoc getBaseIdentifier()
635   {
636
637     // Should this always be absolute?
638
return this.getSystemId();
639   }
640
641   /** line number where the current document event ends.
642    * @serial */

643   private int m_lineNumber;
644
645   /** line number where the current document event ends.
646    * @serial */

647   private int m_endLineNumber;
648
649   /**
650    * Return the line number where the current document event ends.
651    * Note that this is the line position of the first character
652    * after the text associated with the document event.
653    * @return The line number, or -1 if none is available.
654    * @see #getColumnNumber
655    */

656   public int getEndLineNumber()
657   {
658     return m_endLineNumber;
659   }
660
661   /**
662    * Return the line number where the current document event ends.
663    * Note that this is the line position of the first character
664    * after the text associated with the document event.
665    * @return The line number, or -1 if none is available.
666    * @see #getColumnNumber
667    */

668   public int getLineNumber()
669   {
670     return m_lineNumber;
671   }
672
673   /** the column number where the current document event ends.
674    * @serial */

675   private int m_columnNumber;
676
677   /** the column number where the current document event ends.
678    * @serial */

679   private int m_endColumnNumber;
680
681   /**
682    * Return the column number where the current document event ends.
683    * Note that this is the column number of the first
684    * character after the text associated with the document
685    * event. The first column in a line is position 1.
686    * @return The column number, or -1 if none is available.
687    * @see #getLineNumber
688    */

689   public int getEndColumnNumber()
690   {
691     return m_endColumnNumber;
692   }
693
694   /**
695    * Return the column number where the current document event ends.
696    * Note that this is the column number of the first
697    * character after the text associated with the document
698    * event. The first column in a line is position 1.
699    * @return The column number, or -1 if none is available.
700    * @see #getLineNumber
701    */

702   public int getColumnNumber()
703   {
704     return m_columnNumber;
705   }
706
707   /**
708    * Return the public identifier for the current document event.
709    * <p>This will be the public identifier
710    * @return A string containing the public identifier, or
711    * null if none is available.
712    * @see #getSystemId
713    */

714   public String JavaDoc getPublicId()
715   {
716     return (null != m_parentNode) ? m_parentNode.getPublicId() : null;
717   }
718
719   /**
720    * Return the system identifier for the current document event.
721    *
722    * <p>If the system identifier is a URL, the parser must resolve it
723    * fully before passing it to the application.</p>
724    *
725    * @return A string containing the system identifier, or null
726    * if none is available.
727    * @see #getPublicId
728    */

729   public String JavaDoc getSystemId()
730   {
731     Stylesheet sheet=getStylesheet();
732     return (sheet==null) ? null : sheet.getHref();
733   }
734
735   /**
736    * Set the location information for this element.
737    *
738    * @param locator Source Locator with location information for this element
739    */

740   public void setLocaterInfo(SourceLocator JavaDoc locator)
741   {
742     m_lineNumber = locator.getLineNumber();
743     m_columnNumber = locator.getColumnNumber();
744   }
745   
746   /**
747    * Set the end location information for this element.
748    *
749    * @param locator Source Locator with location information for this element
750    */

751   public void setEndLocaterInfo(SourceLocator JavaDoc locator)
752   {
753     m_endLineNumber = locator.getLineNumber();
754     m_endColumnNumber = locator.getColumnNumber();
755   }
756
757   /**
758    * Tell if this element has the default space handling
759    * turned off or on according to the xml:space attribute.
760    * @serial
761    */

762   private boolean m_defaultSpace = true;
763
764   /**
765    * Tell if this element only has one text child, for optimization purposes.
766    * @serial
767    */

768   private boolean m_hasTextLitOnly = false;
769
770   /**
771    * Tell if this element only has one text child, for optimization purposes.
772    * @serial
773    */

774   protected boolean m_hasVariableDecl = false;
775   
776   public boolean hasVariableDecl()
777   {
778     return m_hasVariableDecl;
779   }
780
781   /**
782    * Set the "xml:space" attribute.
783    * A text node is preserved if an ancestor element of the text node
784    * has an xml:space attribute with a value of preserve, and
785    * no closer ancestor element has xml:space with a value of default.
786    * @see <a HREF="http://www.w3.org/TR/xslt#strip">strip in XSLT Specification</a>
787    * @see <a HREF="http://www.w3.org/TR/xslt#section-Creating-Text">section-Creating-Text in XSLT Specification</a>
788    *
789    * @param v Enumerated value, either Constants.ATTRVAL_PRESERVE
790    * or Constants.ATTRVAL_STRIP.
791    */

792   public void setXmlSpace(int v)
793   {
794     m_defaultSpace = ((Constants.ATTRVAL_STRIP == v) ? true : false);
795   }
796
797   /**
798    * Get the "xml:space" attribute.
799    * A text node is preserved if an ancestor element of the text node
800    * has an xml:space attribute with a value of preserve, and
801    * no closer ancestor element has xml:space with a value of default.
802    * @see <a HREF="http://www.w3.org/TR/xslt#strip">strip in XSLT Specification</a>
803    * @see <a HREF="http://www.w3.org/TR/xslt#section-Creating-Text">section-Creating-Text in XSLT Specification</a>
804    *
805    * @return The value of the xml:space attribute
806    */

807   public boolean getXmlSpace()
808   {
809     return m_defaultSpace;
810   }
811
812   /**
813    * The list of namespace declarations for this element only.
814    * @serial
815    */

816   private Vector JavaDoc m_declaredPrefixes;
817
818   /**
819    * Return a table that contains all prefixes available
820    * within this element context.
821    *
822    * @return Vector containing the prefixes available within this
823    * element context
824    */

825   public Vector JavaDoc getDeclaredPrefixes()
826   {
827     return m_declaredPrefixes;
828   }
829
830   /**
831    * From the SAX2 helper class, set the namespace table for
832    * this element. Take care to call resolveInheritedNamespaceDecls.
833    * after all namespace declarations have been added.
834    *
835    * @param nsSupport non-null reference to NamespaceSupport from
836    * the ContentHandler.
837    *
838    * @throws TransformerException
839    */

840   public void setPrefixes(NamespaceSupport JavaDoc nsSupport) throws TransformerException JavaDoc
841   {
842     setPrefixes(nsSupport, false);
843   }
844
845   /**
846    * Copy the namespace declarations from the NamespaceSupport object.
847    * Take care to call resolveInheritedNamespaceDecls.
848    * after all namespace declarations have been added.
849    *
850    * @param nsSupport non-null reference to NamespaceSupport from
851    * the ContentHandler.
852    * @param excludeXSLDecl true if XSLT namespaces should be ignored.
853    *
854    * @throws TransformerException
855    */

856   public void setPrefixes(NamespaceSupport JavaDoc nsSupport, boolean excludeXSLDecl)
857           throws TransformerException JavaDoc
858   {
859
860     Enumeration JavaDoc decls = nsSupport.getDeclaredPrefixes();
861
862     while (decls.hasMoreElements())
863     {
864       String JavaDoc prefix = (String JavaDoc) decls.nextElement();
865
866       if (null == m_declaredPrefixes)
867         m_declaredPrefixes = new Vector JavaDoc();
868
869       String JavaDoc uri = nsSupport.getURI(prefix);
870
871       if (excludeXSLDecl && uri.equals(Constants.S_XSLNAMESPACEURL))
872         continue;
873
874       // System.out.println("setPrefixes - "+prefix+", "+uri);
875
XMLNSDecl decl = new XMLNSDecl(prefix, uri, false);
876
877       m_declaredPrefixes.addElement(decl);
878     }
879   }
880
881   /**
882    * Fullfill the PrefixResolver interface. Calling this for this class
883    * will throw an error.
884    *
885    * @param prefix The prefix to look up, which may be an empty string ("")
886    * for the default Namespace.
887    * @param context The node context from which to look up the URI.
888    *
889    * @return null if the error listener does not choose to throw an exception.
890    */

891   public String JavaDoc getNamespaceForPrefix(String JavaDoc prefix, org.w3c.dom.Node JavaDoc context)
892   {
893     this.error(XSLTErrorResources.ER_CANT_RESOLVE_NSPREFIX, null);
894
895     return null;
896   }
897
898   /**
899    * Given a namespace, get the corrisponding prefix.
900    * 9/15/00: This had been iteratively examining the m_declaredPrefixes
901    * field for this node and its parents. That makes life difficult for
902    * the compilation experiment, which doesn't have a static vector of
903    * local declarations. Replaced a recursive solution, which permits
904    * easier subclassing/overriding.
905    *
906    * @param prefix non-null reference to prefix string, which should map
907    * to a namespace URL.
908    *
909    * @return The namespace URL that the prefix maps to, or null if no
910    * mapping can be found.
911    */

912   public String JavaDoc getNamespaceForPrefix(String JavaDoc prefix)
913   {
914 // if (null != prefix && prefix.equals("xmlns"))
915
// {
916
// return Constants.S_XMLNAMESPACEURI;
917
// }
918

919     Vector JavaDoc nsDecls = m_declaredPrefixes;
920
921     if (null != nsDecls)
922     {
923       int n = nsDecls.size();
924       if(prefix.equals(Constants.ATTRVAL_DEFAULT_PREFIX))
925       {
926         prefix = "";
927       }
928
929       for (int i = 0; i < n; i++)
930       {
931         XMLNSDecl decl = (XMLNSDecl) nsDecls.elementAt(i);
932
933         if (prefix.equals(decl.getPrefix()))
934           return decl.getURI();
935       }
936     }
937
938     // Not found; ask our ancestors
939
if (null != m_parentNode)
940       return m_parentNode.getNamespaceForPrefix(prefix);
941
942     // JJK: No ancestors; try implicit
943
// %REVIEW% Are there literals somewhere that we should use instead?
944
// %REVIEW% Is this really the best place to patch?
945
if("xml".equals(prefix))
946       return "http://www.w3.org/XML/1998/namespace";
947
948     // No parent, so no definition
949
return null;
950   }
951
952   /**
953    * The table of {@link XMLNSDecl}s for this element
954    * and all parent elements, screened for excluded prefixes.
955    * @serial
956    */

957   Vector JavaDoc m_prefixTable;
958
959   /**
960    * Return a table that contains all prefixes available
961    * within this element context.
962    *
963    * @return reference to vector of {@link XMLNSDecl}s, which may be null.
964    */

965   public Vector JavaDoc getPrefixes()
966   {
967     return m_prefixTable;
968   }
969   
970   /**
971    * Get whether or not the passed URL is contained flagged by
972    * the "extension-element-prefixes" property. This method is overridden
973    * by {@link ElemLiteralResult#containsExcludeResultPrefix}.
974    * @see <a HREF="http://www.w3.org/TR/xslt#extension-element">extension-element in XSLT Specification</a>
975    *
976    * @param prefix non-null reference to prefix that might be excluded.
977    *
978    * @return true if the prefix should normally be excluded.
979    */

980   public boolean containsExcludeResultPrefix(String JavaDoc prefix, String JavaDoc uri)
981   {
982     ElemTemplateElement parent = this.getParentElem();
983     if(null != parent)
984       return parent.containsExcludeResultPrefix(prefix, uri);
985       
986     return false;
987   }
988
989   /**
990    * Tell if the result namespace decl should be excluded. Should be called before
991    * namespace aliasing (I think).
992    *
993    * @param prefix non-null reference to prefix.
994    * @param uri reference to namespace that prefix maps to, which is protected
995    * for null, but should really never be passed as null.
996    *
997    * @return true if the given namespace should be excluded.
998    *
999    * @throws TransformerException
1000   */

1001  private boolean excludeResultNSDecl(String JavaDoc prefix, String JavaDoc uri)
1002          throws TransformerException JavaDoc
1003  {
1004
1005    if (uri != null)
1006    {
1007      if (uri.equals(Constants.S_XSLNAMESPACEURL)
1008              || getStylesheet().containsExtensionElementURI(uri))
1009        return true;
1010
1011      if (containsExcludeResultPrefix(prefix, uri))
1012        return true;
1013    }
1014
1015    return false;
1016  }
1017  
1018  /**
1019   * Combine the parent's namespaces with this namespace
1020   * for fast processing, taking care to reference the
1021   * parent's namespace if this namespace adds nothing new.
1022   * (Recursive method, walking the elements depth-first,
1023   * processing parents before children).
1024   * Note that this method builds m_prefixTable with aliased
1025   * namespaces, *not* the original namespaces.
1026   *
1027   * @throws TransformerException
1028   */

1029  public void resolvePrefixTables() throws TransformerException JavaDoc
1030  {
1031    // Always start with a fresh prefix table!
1032
m_prefixTable = null;
1033
1034    // If we have declared declarations, then we look for
1035
// a parent that has namespace decls, and add them
1036
// to this element's decls. Otherwise we just point
1037
// to the parent that has decls.
1038
if (null != this.m_declaredPrefixes)
1039    {
1040      StylesheetRoot stylesheet = this.getStylesheetRoot();
1041      
1042      // Add this element's declared prefixes to the
1043
// prefix table.
1044
int n = m_declaredPrefixes.size();
1045
1046      for (int i = 0; i < n; i++)
1047      {
1048        XMLNSDecl decl = (XMLNSDecl) m_declaredPrefixes.elementAt(i);
1049        String JavaDoc prefix = decl.getPrefix();
1050        String JavaDoc uri = decl.getURI();
1051        if(null == uri)
1052          uri = "";
1053        boolean shouldExclude = excludeResultNSDecl(prefix, uri);
1054
1055        // Create a new prefix table if one has not already been created.
1056
if (null == m_prefixTable)
1057          m_prefixTable = new Vector JavaDoc();
1058
1059        NamespaceAlias nsAlias = stylesheet.getNamespaceAliasComposed(uri);
1060        if(null != nsAlias)
1061        {
1062          // Should I leave the non-aliased element in the table as
1063
// an excluded element?
1064

1065          // The exclusion should apply to the non-aliased prefix, so
1066
// we don't calculate it here. -sb
1067
// Use stylesheet prefix, as per xsl WG
1068
decl = new XMLNSDecl(nsAlias.getStylesheetPrefix(),
1069                              nsAlias.getResultNamespace(), shouldExclude);
1070        }
1071        else
1072          decl = new XMLNSDecl(prefix, uri, shouldExclude);
1073
1074        m_prefixTable.addElement(decl);
1075        
1076      }
1077    }
1078
1079    ElemTemplateElement parent = this.getParentNodeElem();
1080
1081    if (null != parent)
1082    {
1083
1084      // The prefix table of the parent should never be null!
1085
Vector JavaDoc prefixes = parent.m_prefixTable;
1086
1087      if (null == m_prefixTable && !needToCheckExclude())
1088      {
1089
1090        // Nothing to combine, so just use parent's table!
1091
this.m_prefixTable = parent.m_prefixTable;
1092      }
1093      else
1094      {
1095
1096        // Add the prefixes from the parent's prefix table.
1097
int n = prefixes.size();
1098        
1099        for (int i = 0; i < n; i++)
1100        {
1101          XMLNSDecl decl = (XMLNSDecl) prefixes.elementAt(i);
1102          boolean shouldExclude = excludeResultNSDecl(decl.getPrefix(),
1103                                                      decl.getURI());
1104
1105          if (shouldExclude != decl.getIsExcluded())
1106          {
1107            decl = new XMLNSDecl(decl.getPrefix(), decl.getURI(),
1108                                 shouldExclude);
1109          }
1110          
1111          //m_prefixTable.addElement(decl);
1112
addOrReplaceDecls(decl);
1113        }
1114      }
1115    }
1116    else if (null == m_prefixTable)
1117    {
1118
1119      // Must be stylesheet element without any result prefixes!
1120
m_prefixTable = new Vector JavaDoc();
1121    }
1122  }
1123  
1124  /**
1125   * Add or replace this namespace declaration in list
1126   * of namespaces in scope for this element.
1127   *
1128   * @param newDecl namespace declaration to add to list
1129   */

1130  void addOrReplaceDecls(XMLNSDecl newDecl)
1131  {
1132      int n = m_prefixTable.size();
1133
1134        for (int i = n - 1; i >= 0; i--)
1135        {
1136          XMLNSDecl decl = (XMLNSDecl) m_prefixTable.elementAt(i);
1137
1138          if (decl.getPrefix().equals(newDecl.getPrefix()))
1139          {
1140            return;
1141          }
1142        }
1143      m_prefixTable.addElement(newDecl);
1144    
1145  }
1146  
1147  /**
1148   * Return whether we need to check namespace prefixes
1149   * against and exclude result prefixes list.
1150   */

1151  boolean needToCheckExclude()
1152  {
1153    return false;
1154  }
1155
1156  /**
1157   * Send startPrefixMapping events to the result tree handler
1158   * for all declared prefix mappings in the stylesheet.
1159   *
1160   * @param transformer non-null reference to the the current transform-time state.
1161   *
1162   * @throws TransformerException
1163   */

1164  void executeNSDecls(TransformerImpl transformer) throws TransformerException JavaDoc
1165  {
1166       executeNSDecls(transformer, null);
1167  }
1168
1169  /**
1170   * Send startPrefixMapping events to the result tree handler
1171   * for all declared prefix mappings in the stylesheet.
1172   *
1173   * @param transformer non-null reference to the the current transform-time state.
1174   * @param ignorePrefix string prefix to not startPrefixMapping
1175   *
1176   * @throws TransformerException
1177   */

1178  void executeNSDecls(TransformerImpl transformer, String JavaDoc ignorePrefix) throws TransformerException JavaDoc
1179  {
1180    try
1181    {
1182      if (null != m_prefixTable)
1183      {
1184        SerializationHandler rhandler = transformer.getResultTreeHandler();
1185        int n = m_prefixTable.size();
1186
1187        for (int i = n - 1; i >= 0; i--)
1188        {
1189          XMLNSDecl decl = (XMLNSDecl) m_prefixTable.elementAt(i);
1190
1191          if (!decl.getIsExcluded() && !(null != ignorePrefix && decl.getPrefix().equals(ignorePrefix)))
1192          {
1193            rhandler.startPrefixMapping(decl.getPrefix(), decl.getURI(), true);
1194          }
1195        }
1196      }
1197    }
1198    catch(org.xml.sax.SAXException JavaDoc se)
1199    {
1200      throw new TransformerException JavaDoc(se);
1201    }
1202  }
1203
1204  /**
1205   * Send endPrefixMapping events to the result tree handler
1206   * for all declared prefix mappings in the stylesheet.
1207   *
1208   * @param transformer non-null reference to the the current transform-time state.
1209   *
1210   * @throws TransformerException
1211   */

1212  void unexecuteNSDecls(TransformerImpl transformer) throws TransformerException JavaDoc
1213  {
1214       unexecuteNSDecls(transformer, null);
1215  }
1216
1217  /**
1218   * Send endPrefixMapping events to the result tree handler
1219   * for all declared prefix mappings in the stylesheet.
1220   *
1221   * @param transformer non-null reference to the the current transform-time state.
1222   * @param ignorePrefix string prefix to not endPrefixMapping
1223   *
1224   * @throws TransformerException
1225   */

1226  void unexecuteNSDecls(TransformerImpl transformer, String JavaDoc ignorePrefix) throws TransformerException JavaDoc
1227  {
1228 
1229    try
1230    {
1231      if (null != m_prefixTable)
1232      {
1233        SerializationHandler rhandler = transformer.getResultTreeHandler();
1234        int n = m_prefixTable.size();
1235
1236        for (int i = 0; i < n; i++)
1237        {
1238          XMLNSDecl decl = (XMLNSDecl) m_prefixTable.elementAt(i);
1239
1240          if (!decl.getIsExcluded() && !(null != ignorePrefix && decl.getPrefix().equals(ignorePrefix)))
1241          {
1242            rhandler.endPrefixMapping(decl.getPrefix());
1243          }
1244        }
1245      }
1246    }
1247    catch(org.xml.sax.SAXException JavaDoc se)
1248    {
1249      throw new TransformerException JavaDoc(se);
1250    }
1251  }
1252  
1253  /** The *relative* document order number of this element.
1254   * @serial */

1255  protected int m_docOrderNumber = -1;
1256  
1257  /**
1258   * Set the UID (document order index).
1259   *
1260   * @param kIndex Index of this child.
1261   */

1262  public void setUid(int i)
1263  {
1264    m_docOrderNumber = i;
1265  }
1266
1267  /**
1268   * Get the UID (document order index).
1269   *
1270   * @return Index of this child
1271   */

1272  public int getUid()
1273  {
1274    return m_docOrderNumber;
1275  }
1276
1277
1278  /**
1279   * Parent node.
1280   * @serial
1281   */

1282  protected ElemTemplateElement m_parentNode;
1283
1284  /**
1285   * Get the parent as a Node.
1286   *
1287   * @return This node's parent node
1288   */

1289  public Node getParentNode()
1290  {
1291    return m_parentNode;
1292  }
1293
1294  /**
1295   * Get the parent as an ElemTemplateElement.
1296   *
1297   * @return This node's parent as an ElemTemplateElement
1298   */

1299  public ElemTemplateElement getParentElem()
1300  {
1301    return m_parentNode;
1302  }
1303
1304  /**
1305   * Set the parent as an ElemTemplateElement.
1306   *
1307   * @param parent This node's parent as an ElemTemplateElement
1308   */

1309  public void setParentElem(ElemTemplateElement p)
1310  {
1311    m_parentNode = p;
1312  }
1313
1314  /**
1315   * Next sibling.
1316   * @serial
1317   */

1318  ElemTemplateElement m_nextSibling;
1319
1320  /**
1321   * Get the next sibling (as a Node) or return null.
1322   *
1323   * @return this node's next sibling or null
1324   */

1325  public Node getNextSibling()
1326  {
1327    return m_nextSibling;
1328  }
1329
1330  /**
1331   * Get the previous sibling (as a Node) or return null.
1332   * Note that this may be expensive if the parent has many kids;
1333   * we accept that price in exchange for avoiding the prev pointer
1334   * TODO: If we were sure parents and sibs are always ElemTemplateElements,
1335   * we could hit the fields directly rather than thru accessors.
1336   *
1337   * @return This node's previous sibling or null
1338   */

1339  public Node getPreviousSibling()
1340  {
1341
1342    Node walker = getParentNode(), prev = null;
1343
1344    if (walker != null)
1345      for (walker = walker.getFirstChild(); walker != null;
1346              prev = walker, walker = walker.getNextSibling())
1347      {
1348        if (walker == this)
1349          return prev;
1350      }
1351
1352    return null;
1353  }
1354
1355  /**
1356   * Get the previous sibling (as a Node) or return null.
1357   * Note that this may be expensive if the parent has many kids;
1358   * we accept that price in exchange for avoiding the prev pointer
1359   * TODO: If we were sure parents and sibs are always ElemTemplateElements,
1360   * we could hit the fields directly rather than thru accessors.
1361   *
1362   * @return This node's previous sibling or null
1363   */

1364  public ElemTemplateElement getPreviousSiblingElem()
1365  {
1366
1367    ElemTemplateElement walker = getParentNodeElem();
1368    ElemTemplateElement prev = null;
1369
1370    if (walker != null)
1371      for (walker = walker.getFirstChildElem(); walker != null;
1372              prev = walker, walker = walker.getNextSiblingElem())
1373      {
1374        if (walker == this)
1375          return prev;
1376      }
1377
1378    return null;
1379  }
1380
1381
1382  /**
1383   * Get the next sibling (as a ElemTemplateElement) or return null.
1384   *
1385   * @return This node's next sibling (as a ElemTemplateElement) or null
1386   */

1387  public ElemTemplateElement getNextSiblingElem()
1388  {
1389    return m_nextSibling;
1390  }
1391  
1392  /**
1393   * Get the parent element.
1394   *
1395   * @return This node's next parent (as a ElemTemplateElement) or null
1396   */

1397  public ElemTemplateElement getParentNodeElem()
1398  {
1399    return m_parentNode;
1400  }
1401
1402
1403  /**
1404   * First child.
1405   * @serial
1406   */

1407  ElemTemplateElement m_firstChild;
1408
1409  /**
1410   * Get the first child as a Node.
1411   *
1412   * @return This node's first child or null
1413   */

1414  public Node getFirstChild()
1415  {
1416    return m_firstChild;
1417  }
1418
1419  /**
1420   * Get the first child as a ElemTemplateElement.
1421   *
1422   * @return This node's first child (as a ElemTemplateElement) or null
1423   */

1424  public ElemTemplateElement getFirstChildElem()
1425  {
1426    return m_firstChild;
1427  }
1428
1429  /**
1430   * Get the last child.
1431   *
1432   * @return This node's last child
1433   */

1434  public Node getLastChild()
1435  {
1436
1437    ElemTemplateElement lastChild = null;
1438
1439    for (ElemTemplateElement node = m_firstChild; node != null;
1440            node = node.m_nextSibling)
1441    {
1442      lastChild = node;
1443    }
1444
1445    return lastChild;
1446  }
1447
1448  /**
1449   * Get the last child.
1450   *
1451   * @return This node's last child
1452   */

1453  public ElemTemplateElement getLastChildElem()
1454  {
1455
1456    ElemTemplateElement lastChild = null;
1457
1458    for (ElemTemplateElement node = m_firstChild; node != null;
1459            node = node.m_nextSibling)
1460    {
1461      lastChild = node;
1462    }
1463
1464    return lastChild;
1465  }
1466
1467
1468  /** DOM backpointer that this element originated from. */
1469  transient private org.w3c.dom.Node JavaDoc m_DOMBackPointer;
1470
1471  /**
1472   * If this stylesheet was created from a DOM, get the
1473   * DOM backpointer that this element originated from.
1474   * For tooling use.
1475   *
1476   * @return DOM backpointer that this element originated from or null.
1477   */

1478  public org.w3c.dom.Node JavaDoc getDOMBackPointer()
1479  {
1480    return m_DOMBackPointer;
1481  }
1482
1483  /**
1484   * If this stylesheet was created from a DOM, set the
1485   * DOM backpointer that this element originated from.
1486   * For tooling use.
1487   *
1488   * @param n DOM backpointer that this element originated from.
1489   */

1490  public void setDOMBackPointer(org.w3c.dom.Node JavaDoc n)
1491  {
1492    m_DOMBackPointer = n;
1493  }
1494
1495  /**
1496   * Compares this object with the specified object for precedence order.
1497   * The order is determined by the getImportCountComposed() of the containing
1498   * composed stylesheet and the getUid() of this element.
1499   * Returns a negative integer, zero, or a positive integer as this
1500   * object is less than, equal to, or greater than the specified object.
1501   *
1502   * @param o The object to be compared to this object
1503   * @return a negative integer, zero, or a positive integer as this object is
1504   * less than, equal to, or greater than the specified object.
1505   * @throws ClassCastException if the specified object's
1506   * type prevents it from being compared to this Object.
1507   */

1508  public int compareTo(Object JavaDoc o) throws ClassCastException JavaDoc {
1509    
1510    ElemTemplateElement ro = (ElemTemplateElement) o;
1511    int roPrecedence = ro.getStylesheetComposed().getImportCountComposed();
1512    int myPrecedence = this.getStylesheetComposed().getImportCountComposed();
1513
1514    if (myPrecedence < roPrecedence)
1515      return -1;
1516    else if (myPrecedence > roPrecedence)
1517      return 1;
1518    else
1519      return this.getUid() - ro.getUid();
1520  }
1521  
1522  /**
1523   * Get information about whether or not an element should strip whitespace.
1524   * @see <a HREF="http://www.w3.org/TR/xslt#strip">strip in XSLT Specification</a>
1525   *
1526   * @param support The XPath runtime state.
1527   * @param targetElement Element to check
1528   *
1529   * @return true if the whitespace should be stripped.
1530   *
1531   * @throws TransformerException
1532   */

1533  public boolean shouldStripWhiteSpace(
1534          org.apache.xpath.XPathContext support,
1535          org.w3c.dom.Element JavaDoc targetElement) throws TransformerException JavaDoc
1536  {
1537    StylesheetRoot sroot = this.getStylesheetRoot();
1538    return (null != sroot) ? sroot.shouldStripWhiteSpace(support, targetElement) :false;
1539  }
1540  
1541  /**
1542   * Get information about whether or not whitespace can be stripped.
1543   * @see <a HREF="http://www.w3.org/TR/xslt#strip">strip in XSLT Specification</a>
1544   *
1545   * @return true if the whitespace can be stripped.
1546   */

1547  public boolean canStripWhiteSpace()
1548  {
1549    StylesheetRoot sroot = this.getStylesheetRoot();
1550    return (null != sroot) ? sroot.canStripWhiteSpace() : false;
1551  }
1552  
1553  /**
1554   * Tell if this element can accept variable declarations.
1555   * @return true if the element can accept and process variable declarations.
1556   */

1557  public boolean canAcceptVariables()
1558  {
1559    return true;
1560  }
1561  
1562  //=============== ExpressionNode methods ================
1563

1564  /**
1565   * Set the parent of this node.
1566   * @param n Must be a ElemTemplateElement.
1567   */

1568  public void exprSetParent(ExpressionNode n)
1569  {
1570    // This obviously requires that only a ElemTemplateElement can
1571
// parent a node of this type.
1572
setParentElem((ElemTemplateElement)n);
1573  }
1574  
1575  /**
1576   * Get the ExpressionNode parent of this node.
1577   */

1578  public ExpressionNode exprGetParent()
1579  {
1580    return getParentElem();
1581  }
1582
1583  /**
1584   * This method tells the node to add its argument to the node's
1585   * list of children.
1586   * @param n Must be a ElemTemplateElement.
1587   */

1588  public void exprAddChild(ExpressionNode n, int i)
1589  {
1590    appendChild((ElemTemplateElement)n);
1591  }
1592
1593  /** This method returns a child node. The children are numbered
1594     from zero, left to right. */

1595  public ExpressionNode exprGetChild(int i)
1596  {
1597    return (ExpressionNode)item(i);
1598  }
1599
1600  /** Return the number of children the node has. */
1601  public int exprGetNumChildren()
1602  {
1603    return getLength();
1604  }
1605  
1606  /**
1607   * Accept a visitor and call the appropriate method
1608   * for this class.
1609   *
1610   * @param visitor The visitor whose appropriate method will be called.
1611   * @return true if the children of the object should be visited.
1612   */

1613  protected boolean accept(XSLTVisitor visitor)
1614  {
1615    return visitor.visitInstruction(this);
1616  }
1617
1618  /**
1619   * @see XSLTVisitable#callVisitors(XSLTVisitor)
1620   */

1621  public void callVisitors(XSLTVisitor visitor)
1622  {
1623    if(accept(visitor))
1624    {
1625        callChildVisitors(visitor);
1626    }
1627  }
1628
1629  /**
1630   * Call the children visitors.
1631   * @param visitor The visitor whose appropriate method will be called.
1632   */

1633  protected void callChildVisitors(XSLTVisitor visitor, boolean callAttributes)
1634  {
1635    for (ElemTemplateElement node = m_firstChild;
1636      node != null;
1637      node = node.m_nextSibling)
1638      {
1639      node.callVisitors(visitor);
1640    }
1641  }
1642  
1643  /**
1644   * Call the children visitors.
1645   * @param visitor The visitor whose appropriate method will be called.
1646   */

1647  protected void callChildVisitors(XSLTVisitor visitor)
1648  {
1649    callChildVisitors(visitor, true);
1650  }
1651
1652
1653    /**
1654     * @see PrefixResolver#handlesNullPrefixes()
1655     */

1656    public boolean handlesNullPrefixes() {
1657        return false;
1658    }
1659
1660}
1661
Popular Tags