001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 /*
019 * $Id: ElemLiteralResult.java 1225375 2011-12-28 23:03:43Z mrglavas $
020 */
021 package org.apache.xalan.templates;
022
023 import java.util.ArrayList;
024 import java.util.Iterator;
025 import java.util.List;
026
027 import javax.xml.transform.TransformerException;
028
029 import org.apache.xalan.res.XSLMessages;
030 import org.apache.xalan.res.XSLTErrorResources;
031 import org.apache.xalan.transformer.TransformerImpl;
032 import org.apache.xml.serializer.SerializationHandler;
033 import org.apache.xml.utils.StringVector;
034 import org.apache.xpath.XPathContext;
035 import org.w3c.dom.Attr;
036 import org.w3c.dom.DOMException;
037 import org.w3c.dom.Document;
038 import org.w3c.dom.Element;
039 import org.w3c.dom.NamedNodeMap;
040 import org.w3c.dom.Node;
041 import org.w3c.dom.NodeList;
042 import org.w3c.dom.TypeInfo;
043 import org.w3c.dom.UserDataHandler;
044 import org.xml.sax.SAXException;
045
046 /**
047 * Implement a Literal Result Element.
048 * @see <a href="http://www.w3.org/TR/xslt#literal-result-element">literal-result-element in XSLT Specification</a>
049 * @xsl.usage advanced
050 */
051 public class ElemLiteralResult extends ElemUse
052 {
053 static final long serialVersionUID = -8703409074421657260L;
054
055 /** The return value as Empty String. */
056 private static final String EMPTYSTRING = "";
057
058 /**
059 * Tells if this element represents a root element
060 * that is also the stylesheet element.
061 * TODO: This should be a derived class.
062 * @serial
063 */
064 private boolean isLiteralResultAsStylesheet = false;
065
066 /**
067 * Set whether this element represents a root element
068 * that is also the stylesheet element.
069 *
070 *
071 * @param b boolean flag indicating whether this element
072 * represents a root element that is also the stylesheet element.
073 */
074 public void setIsLiteralResultAsStylesheet(boolean b)
075 {
076 isLiteralResultAsStylesheet = b;
077 }
078
079 /**
080 * Return whether this element represents a root element
081 * that is also the stylesheet element.
082 *
083 *
084 * @return boolean flag indicating whether this element
085 * represents a root element that is also the stylesheet element.
086 */
087 public boolean getIsLiteralResultAsStylesheet()
088 {
089 return isLiteralResultAsStylesheet;
090 }
091
092 /**
093 * This function is called after everything else has been
094 * recomposed, and allows the template to set remaining
095 * values that may be based on some other property that
096 * depends on recomposition.
097 */
098 public void compose(StylesheetRoot sroot) throws TransformerException
099 {
100 super.compose(sroot);
101 StylesheetRoot.ComposeState cstate = sroot.getComposeState();
102 java.util.Vector vnames = cstate.getVariableNames();
103 if (null != m_avts)
104 {
105 int nAttrs = m_avts.size();
106
107 for (int i = (nAttrs - 1); i >= 0; i--)
108 {
109 AVT avt = (AVT) m_avts.get(i);
110 avt.fixupVariables(vnames, cstate.getGlobalsSize());
111 }
112 }
113 }
114
115 /**
116 * The created element node will have the attribute nodes
117 * that were present on the element node in the stylesheet tree,
118 * other than attributes with names in the XSLT namespace.
119 * @serial
120 */
121 private List m_avts = null;
122
123 /** List of attributes with the XSLT namespace.
124 * @serial */
125 private List m_xslAttr = null;
126
127 /**
128 * Set a literal result attribute (AVTs only).
129 *
130 * @param avt literal result attribute to add (AVT only)
131 */
132 public void addLiteralResultAttribute(AVT avt)
133 {
134
135 if (null == m_avts)
136 m_avts = new ArrayList();
137
138 m_avts.add(avt);
139 }
140
141 /**
142 * Set a literal result attribute (used for xsl attributes).
143 *
144 * @param att literal result attribute to add
145 */
146 public void addLiteralResultAttribute(String att)
147 {
148
149 if (null == m_xslAttr)
150 m_xslAttr = new ArrayList();
151
152 m_xslAttr.add(att);
153 }
154
155 /**
156 * Set the "xml:space" attribute.
157 * A text node is preserved if an ancestor element of the text node
158 * has an xml:space attribute with a value of preserve, and
159 * no closer ancestor element has xml:space with a value of default.
160 * @see <a href="http://www.w3.org/TR/xslt#strip">strip in XSLT Specification</a>
161 * @see <a href="http://www.w3.org/TR/xslt#section-Creating-Text">section-Creating-Text in XSLT Specification</a>
162 *
163 * @param avt Enumerated value, either Constants.ATTRVAL_PRESERVE
164 * or Constants.ATTRVAL_STRIP.
165 */
166 public void setXmlSpace(AVT avt)
167 {
168 // This function is a bit-o-hack, I guess...
169 addLiteralResultAttribute(avt);
170 String val = avt.getSimpleString();
171 if(val.equals("default"))
172 {
173 super.setXmlSpace(Constants.ATTRVAL_STRIP);
174 }
175 else if(val.equals("preserve"))
176 {
177 super.setXmlSpace(Constants.ATTRVAL_PRESERVE);
178 }
179 // else maybe it's a real AVT, so we can't resolve it at this time.
180 }
181
182 /**
183 * Get a literal result attribute by name.
184 *
185 * @param namespaceURI Namespace URI of attribute node to get
186 * @param localName Local part of qualified name of attribute node to get
187 *
188 * @return literal result attribute (AVT)
189 */
190 public AVT getLiteralResultAttributeNS(String namespaceURI, String localName)
191 {
192
193 if (null != m_avts)
194 {
195 int nAttrs = m_avts.size();
196
197 for (int i = (nAttrs - 1); i >= 0; i--)
198 {
199 AVT avt = (AVT) m_avts.get(i);
200
201 if (avt.getName().equals(localName) &&
202 avt.getURI().equals(namespaceURI))
203 {
204 return avt;
205 }
206 } // end for
207 }
208
209 return null;
210 }
211
212 /**
213 * Return the raw value of the attribute.
214 *
215 * @param namespaceURI Namespace URI of attribute node to get
216 * @param localName Local part of qualified name of attribute node to get
217 *
218 * @return The Attr value as a string, or the empty string if that attribute
219 * does not have a specified or default value
220 */
221 public String getAttributeNS(String namespaceURI, String localName)
222 {
223
224 AVT avt = getLiteralResultAttributeNS(namespaceURI, localName);
225
226 if ((null != avt))
227 {
228 return avt.getSimpleString();
229 }
230
231 return EMPTYSTRING;
232 }
233
234 /**
235 * Get a literal result attribute by name. The name is namespaceURI:localname
236 * if namespace is not null.
237 *
238 * @param name Name of literal result attribute to get
239 *
240 * @return literal result attribute (AVT)
241 */
242 public AVT getLiteralResultAttribute(String name)
243 {
244
245 if (null != m_avts)
246 {
247 int nAttrs = m_avts.size();
248 String namespace = null;
249 for (int i = (nAttrs - 1); i >= 0; i--)
250 {
251 AVT avt = (AVT) m_avts.get(i);
252 namespace = avt.getURI();
253
254 if ((namespace != null && (namespace.length() != 0) && (namespace
255 +":"+avt.getName()).equals(name))|| ((namespace == null ||
256 namespace.length() == 0)&& avt.getRawName().equals(name)))
257 {
258 return avt;
259 }
260 } // end for
261 }
262
263 return null;
264 }
265
266 /**
267 * Return the raw value of the attribute.
268 *
269 * @param namespaceURI:localName or localName if the namespaceURI is null of
270 * the attribute to get
271 *
272 * @return The Attr value as a string, or the empty string if that attribute
273 * does not have a specified or default value
274 */
275 public String getAttribute(String rawName)
276 {
277
278 AVT avt = getLiteralResultAttribute(rawName);
279
280 if ((null != avt))
281 {
282 return avt.getSimpleString();
283 }
284
285 return EMPTYSTRING;
286 }
287
288 /**
289 * Get whether or not the passed URL is flagged by
290 * the "extension-element-prefixes" or "exclude-result-prefixes"
291 * properties.
292 * @see <a href="http://www.w3.org/TR/xslt#extension-element">extension-element in XSLT Specification</a>
293 *
294 * @param prefix non-null reference to prefix that might be excluded.(not currently used)
295 * @param uri reference to namespace that prefix maps to
296 *
297 * @return true if the prefix should normally be excluded.
298 */
299 public boolean containsExcludeResultPrefix(String prefix, String uri)
300 {
301 if (uri == null ||
302 (null == m_excludeResultPrefixes &&
303 null == m_ExtensionElementURIs)
304 )
305 return super.containsExcludeResultPrefix(prefix, uri);
306
307 if (prefix.length() == 0)
308 prefix = Constants.ATTRVAL_DEFAULT_PREFIX;
309
310 // This loop is ok here because this code only runs during
311 // stylesheet compile time.
312 if(m_excludeResultPrefixes!=null)
313 for (int i =0; i< m_excludeResultPrefixes.size(); i++)
314 {
315 if (uri.equals(getNamespaceForPrefix(m_excludeResultPrefixes.elementAt(i))))
316 return true;
317 }
318
319 // JJK Bugzilla 1133: Also check locally-scoped extensions
320 if(m_ExtensionElementURIs!=null && m_ExtensionElementURIs.contains(uri))
321 return true;
322
323 return super.containsExcludeResultPrefix(prefix, uri);
324 }
325
326 /**
327 * Augment resolvePrefixTables, resolving the namespace aliases once
328 * the superclass has resolved the tables.
329 *
330 * @throws TransformerException
331 */
332 public void resolvePrefixTables() throws TransformerException
333 {
334
335 super.resolvePrefixTables();
336
337 StylesheetRoot stylesheet = getStylesheetRoot();
338
339 if ((null != m_namespace) && (m_namespace.length() > 0))
340 {
341 NamespaceAlias nsa = stylesheet.getNamespaceAliasComposed(m_namespace);
342
343 if (null != nsa)
344 {
345 m_namespace = nsa.getResultNamespace();
346
347 // String resultPrefix = nsa.getResultPrefix();
348 String resultPrefix = nsa.getStylesheetPrefix(); // As per xsl WG, Mike Kay
349
350 if ((null != resultPrefix) && (resultPrefix.length() > 0))
351 m_rawName = resultPrefix + ":" + m_localName;
352 else
353 m_rawName = m_localName;
354 }
355 }
356
357 if (null != m_avts)
358 {
359 int n = m_avts.size();
360
361 for (int i = 0; i < n; i++)
362 {
363 AVT avt = (AVT) m_avts.get(i);
364
365 // Should this stuff be a method on AVT?
366 String ns = avt.getURI();
367
368 if ((null != ns) && (ns.length() > 0))
369 {
370 NamespaceAlias nsa =
371 stylesheet.getNamespaceAliasComposed(m_namespace); // %REVIEW% ns?
372
373 if (null != nsa)
374 {
375 String namespace = nsa.getResultNamespace();
376
377 // String resultPrefix = nsa.getResultPrefix();
378 String resultPrefix = nsa.getStylesheetPrefix(); // As per XSL WG
379 String rawName = avt.getName();
380
381 if ((null != resultPrefix) && (resultPrefix.length() > 0))
382 rawName = resultPrefix + ":" + rawName;
383
384 avt.setURI(namespace);
385 avt.setRawName(rawName);
386 }
387 }
388 }
389 }
390 }
391
392 /**
393 * Return whether we need to check namespace prefixes
394 * against the exclude result prefixes or extensions lists.
395 * Note that this will create a new prefix table if one
396 * has not been created already.
397 *
398 * NEEDSDOC ($objectName$) @return
399 */
400 boolean needToCheckExclude()
401 {
402 if (null == m_excludeResultPrefixes && null == getPrefixTable()
403 && m_ExtensionElementURIs==null // JJK Bugzilla 1133
404 )
405 return false;
406 else
407 {
408
409 // Create a new prefix table if one has not already been created.
410 if (null == getPrefixTable())
411 setPrefixTable(new java.util.ArrayList());
412
413 return true;
414 }
415 }
416
417 /**
418 * The namespace of the element to be created.
419 * @serial
420 */
421 private String m_namespace;
422
423 /**
424 * Set the namespace URI of the result element to be created.
425 * Note that after resolvePrefixTables has been called, this will
426 * return the aliased result namespace, not the original stylesheet
427 * namespace.
428 *
429 * @param ns The Namespace URI, or the empty string if the
430 * element has no Namespace URI.
431 */
432 public void setNamespace(String ns)
433 {
434 if(null == ns) // defensive, shouldn't have to do this.
435 ns = "";
436 m_namespace = ns;
437 }
438
439 /**
440 * Get the original namespace of the Literal Result Element.
441 *
442 * %REVIEW% Why isn't this overriding the getNamespaceURI method
443 * rather than introducing a new one?
444 *
445 * @return The Namespace URI, or the empty string if the
446 * element has no Namespace URI.
447 */
448 public String getNamespace()
449 {
450 return m_namespace;
451 }
452
453 /**
454 * The local name of the element to be created.
455 * @serial
456 */
457 private String m_localName;
458
459 /**
460 * Set the local name of the LRE.
461 *
462 * @param localName The local name (without prefix) of the result element
463 * to be created.
464 */
465 public void setLocalName(String localName)
466 {
467 m_localName = localName;
468 }
469
470 /**
471 * Get the local name of the Literal Result Element.
472 * Note that after resolvePrefixTables has been called, this will
473 * return the aliased name prefix, not the original stylesheet
474 * namespace prefix.
475 *
476 * @return The local name (without prefix) of the result element
477 * to be created.
478 */
479 public String getLocalName()
480 {
481 return m_localName;
482 }
483
484 /**
485 * The raw name of the element to be created.
486 * @serial
487 */
488 private String m_rawName;
489
490 /**
491 * Set the raw name of the LRE.
492 *
493 * @param rawName The qualified name (with prefix), or the
494 * empty string if qualified names are not available.
495 */
496 public void setRawName(String rawName)
497 {
498 m_rawName = rawName;
499 }
500
501 /**
502 * Get the raw name of the Literal Result Element.
503 *
504 * @return The qualified name (with prefix), or the
505 * empty string if qualified names are not available.
506 */
507 public String getRawName()
508 {
509 return m_rawName;
510 }
511
512 /**
513 * Get the prefix part of the raw name of the Literal Result Element.
514 *
515 * @return The prefix, or the empty string if noprefix was provided.
516 */
517 public String getPrefix()
518 {
519 int len=m_rawName.length()-m_localName.length()-1;
520 return (len>0)
521 ? m_rawName.substring(0,len)
522 : "";
523 }
524
525
526 /**
527 * The "extension-element-prefixes" property, actually contains URIs.
528 * @serial
529 */
530 private StringVector m_ExtensionElementURIs;
531
532 /**
533 * Set the "extension-element-prefixes" property.
534 * @see <a href="http://www.w3.org/TR/xslt#extension-element">extension-element in XSLT Specification</a>
535 *
536 * @param v Vector of URIs (not prefixes) to set as the "extension-element-prefixes" property
537 */
538 public void setExtensionElementPrefixes(StringVector v)
539 {
540 m_ExtensionElementURIs = v;
541 }
542
543 /**
544 * @see org.w3c.dom.Node
545 *
546 * @return NamedNodeMap
547 */
548 public NamedNodeMap getAttributes()
549 {
550 return new LiteralElementAttributes();
551 }
552
553 public class LiteralElementAttributes implements NamedNodeMap{
554 private int m_count = -1;
555
556 /**
557 * Construct a NameNodeMap.
558 *
559 */
560 public LiteralElementAttributes(){
561 }
562
563 /**
564 * Return the number of Attributes on this Element
565 *
566 * @return The number of nodes in this map. The range of valid child
567 * node indices is <code>0</code> to <code>length-1</code> inclusive
568 */
569 public int getLength()
570 {
571 if (m_count == -1)
572 {
573 if (null != m_avts) m_count = m_avts.size();
574 else m_count = 0;
575 }
576 return m_count;
577 }
578
579 /**
580 * Retrieves a node specified by name.
581 * @param name The <code>nodeName</code> of a node to retrieve.
582 * @return A <code>Node</code> (of any type) with the specified
583 * <code>nodeName</code>, or <code>null</code> if it does not
584 * identify any node in this map.
585 */
586 public Node getNamedItem(String name)
587 {
588 if (getLength() == 0) return null;
589 String uri = null;
590 String localName = name;
591 int index = name.indexOf(":");
592 if (-1 != index){
593 uri = name.substring(0, index);
594 localName = name.substring(index+1);
595 }
596 Node retNode = null;
597 Iterator eum = m_avts.iterator();
598 while (eum.hasNext()){
599 AVT avt = (AVT) eum.next();
600 if (localName.equals(avt.getName()))
601 {
602 String nsURI = avt.getURI();
603 if ((uri == null && nsURI == null)
604 || (uri != null && uri.equals(nsURI)))
605 {
606 retNode = new Attribute(avt, ElemLiteralResult.this);
607 break;
608 }
609 }
610 }
611 return retNode;
612 }
613
614 /**
615 * Retrieves a node specified by local name and namespace URI.
616 * @param namespaceURI Namespace URI of attribute node to get
617 * @param localName Local part of qualified name of attribute node to
618 * get
619 * @return A <code>Node</code> (of any type) with the specified
620 * <code>nodeName</code>, or <code>null</code> if it does not
621 * identify any node in this map.
622 */
623 public Node getNamedItemNS(String namespaceURI, String localName)
624 {
625 if (getLength() == 0) return null;
626 Node retNode = null;
627 Iterator eum = m_avts.iterator();
628 while (eum.hasNext())
629 {
630 AVT avt = (AVT) eum.next();
631 if (localName.equals(avt.getName()))
632 {
633 String nsURI = avt.getURI();
634 if ((namespaceURI == null && nsURI == null)
635 || (namespaceURI != null && namespaceURI.equals(nsURI)))
636 {
637 retNode = new Attribute(avt, ElemLiteralResult.this);
638 break;
639 }
640 }
641 }
642 return retNode;
643 }
644
645 /**
646 * Returns the <code>index</code>th item in the map. If <code>index
647 * </code> is greater than or equal to the number of nodes in this
648 * map, this returns <code>null</code>.
649 * @param i The index of the requested item.
650 * @return The node at the <code>index</code>th position in the map,
651 * or <code>null</code> if that is not a valid index.
652 */
653 public Node item(int i)
654 {
655 if (getLength() == 0 || i >= m_avts.size()) return null;
656 else return
657 new Attribute(((AVT)m_avts.get(i)),
658 ElemLiteralResult.this);
659 }
660
661 /**
662 * @see org.w3c.dom.NamedNodeMap
663 *
664 * @param name of the node to remove
665 *
666 * @return The node removed from this map if a node with such
667 * a name exists.
668 *
669 * @throws DOMException
670 */
671 public Node removeNamedItem(String name) throws DOMException
672 {
673 throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
674 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR);
675 return null;
676 }
677
678 /**
679 * @see org.w3c.dom.NamedNodeMap
680 *
681 * @param namespaceURI Namespace URI of the node to remove
682 * @param localName Local part of qualified name of the node to remove
683 *
684 * @return The node removed from this map if a node with such a local
685 * name and namespace URI exists
686 *
687 * @throws DOMException
688 */
689 public Node removeNamedItemNS(String namespaceURI, String localName)
690 throws DOMException
691 {
692 throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
693 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR);
694 return null;
695 }
696
697 /**
698 * Unimplemented. See org.w3c.dom.NamedNodeMap
699 *
700 * @param A node to store in this map
701 *
702 * @return If the new Node replaces an existing node the replaced
703 * Node is returned, otherwise null is returned
704 *
705 * @throws DOMException
706 */
707 public Node setNamedItem(Node arg) throws DOMException
708 {
709 throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
710 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR);
711 return null;
712 }
713
714 /**
715 * Unimplemented. See org.w3c.dom.NamedNodeMap
716 *
717 * @param A node to store in this map
718 *
719 * @return If the new Node replaces an existing node the replaced
720 * Node is returned, otherwise null is returned
721 *
722 * @throws DOMException
723 */
724 public Node setNamedItemNS(Node arg) throws DOMException
725 {
726 throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
727 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR);
728 return null;
729 }
730 }
731
732 public class Attribute implements Attr{
733 private AVT m_attribute;
734 private Element m_owner = null;
735 /**
736 * Construct a Attr.
737 *
738 */
739 public Attribute(AVT avt, Element elem){
740 m_attribute = avt;
741 m_owner = elem;
742 }
743
744 /**
745 * @see org.w3c.dom.Node
746 *
747 * @param newChild New node to append to the list of this node's
748 * children
749 *
750 *
751 * @throws DOMException
752 */
753 public Node appendChild(Node newChild) throws DOMException
754 {
755 throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
756 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR);
757 return null;
758 }
759
760 /**
761 * @see org.w3c.dom.Node
762 *
763 * @param deep Flag indicating whether to clone deep
764 * (clone member variables)
765 *
766 * @return Returns a duplicate of this node
767 */
768 public Node cloneNode(boolean deep)
769 {
770 return new Attribute(m_attribute, m_owner);
771 }
772
773 /**
774 * @see org.w3c.dom.Node
775 *
776 * @return null
777 */
778 public NamedNodeMap getAttributes()
779 {
780 return null;
781 }
782
783 /**
784 * @see org.w3c.dom.Node
785 *
786 * @return a NodeList containing no nodes.
787 */
788 public NodeList getChildNodes()
789 {
790 return new NodeList(){
791 public int getLength(){
792 return 0;
793 }
794 public Node item(int index){
795 return null;
796 }
797 };
798 }
799
800 /**
801 * @see org.w3c.dom.Node
802 *
803 * @return null
804 */
805 public Node getFirstChild()
806 {
807 return null;
808 }
809
810 /**
811 * @see org.w3c.dom.Node
812 *
813 * @return null
814 */
815 public Node getLastChild()
816 {
817 return null;
818 }
819
820 /**
821 * @see org.w3c.dom.Node
822 *
823 * @return the local part of the qualified name of this node
824 */
825 public String getLocalName()
826 {
827 return m_attribute.getName();
828 }
829
830 /**
831 * @see org.w3c.dom.Node
832 *
833 * @return The namespace URI of this node, or null if it is
834 * unspecified
835 */
836 public String getNamespaceURI()
837 {
838 String uri = m_attribute.getURI();
839 return (uri.length() == 0)?null:uri;
840 }
841
842 /**
843 * @see org.w3c.dom.Node
844 *
845 * @return null
846 */
847 public Node getNextSibling()
848 {
849 return null;
850 }
851
852 /**
853 * @see org.w3c.dom.Node
854 *
855 * @return The name of the attribute
856 */
857 public String getNodeName()
858 {
859 String uri = m_attribute.getURI();
860 String localName = getLocalName();
861 return (uri.length() == 0)?localName:uri+":"+localName;
862 }
863
864 /**
865 * @see org.w3c.dom.Node
866 *
867 * @return The node is an Attr
868 */
869 public short getNodeType()
870 {
871 return ATTRIBUTE_NODE;
872 }
873
874 /**
875 * @see org.w3c.dom.Node
876 *
877 * @return The value of the attribute
878 *
879 * @throws DOMException
880 */
881 public String getNodeValue() throws DOMException
882 {
883 return m_attribute.getSimpleString();
884 }
885
886 /**
887 * @see org.w3c.dom.Node
888 *
889 * @return null
890 */
891 public Document getOwnerDocument()
892 {
893 return m_owner.getOwnerDocument();
894 }
895
896 /**
897 * @see org.w3c.dom.Node
898 *
899 * @return the containing element node
900 */
901 public Node getParentNode()
902 {
903 return m_owner;
904 }
905
906 /**
907 * @see org.w3c.dom.Node
908 *
909 * @return The namespace prefix of this node, or null if it is
910 * unspecified
911 */
912 public String getPrefix()
913 {
914 String uri = m_attribute.getURI();
915 String rawName = m_attribute.getRawName();
916 return (uri.length() == 0)?
917 null:rawName.substring(0, rawName.indexOf(":"));
918 }
919
920 /**
921 * @see org.w3c.dom.Node
922 *
923 * @return null
924 */
925 public Node getPreviousSibling()
926 {
927 return null;
928 }
929
930 /**
931 * @see org.w3c.dom.Node
932 *
933 * @return false
934 */
935 public boolean hasAttributes()
936 {
937 return false;
938 }
939
940 /**
941 * @see org.w3c.dom.Node
942 *
943 * @return false
944 */
945 public boolean hasChildNodes()
946 {
947 return false;
948 }
949
950 /**
951 * @see org.w3c.dom.Node
952 *
953 * @param newChild New child node to insert
954 * @param refChild Insert in front of this child
955 *
956 * @return null
957 *
958 * @throws DOMException
959 */
960 public Node insertBefore(Node newChild, Node refChild)
961 throws DOMException
962 {
963 throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
964 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR);
965 return null;
966 }
967
968 /**
969 * @see org.w3c.dom.Node
970 *
971 * @return Returns <code>false</code>
972 * @since DOM Level 2
973 */
974 public boolean isSupported(String feature, String version)
975 {
976 return false;
977 }
978
979 /** @see org.w3c.dom.Node */
980 public void normalize(){}
981
982 /**
983 * @see org.w3c.dom.Node
984 *
985 * @param oldChild Child to be removed
986 *
987 * @return null
988 *
989 * @throws DOMException
990 */
991 public Node removeChild(Node oldChild) throws DOMException
992 {
993 throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
994 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR);
995 return null;
996 }
997
998 /**
999 * @see org.w3c.dom.Node
1000 *
1001 * @param newChild Replace existing child with this one
1002 * @param oldChild Existing child to be replaced
1003 *
1004 * @return null
1005 *
1006 * @throws DOMException
1007 */
1008 public Node replaceChild(Node newChild, Node oldChild) throws DOMException
1009 {
1010 throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
1011 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR);
1012 return null;
1013 }
1014
1015 /**
1016 * @see org.w3c.dom.Node
1017 *
1018 * @param nodeValue Value to set this node to
1019 *
1020 * @throws DOMException
1021 */
1022 public void setNodeValue(String nodeValue) throws DOMException
1023 {
1024 throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
1025 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR);
1026 }
1027
1028 /**
1029 * @see org.w3c.dom.Node
1030 *
1031 * @param prefix Prefix to set for this node
1032 *
1033 * @throws DOMException
1034 */
1035 public void setPrefix(String prefix) throws DOMException
1036 {
1037 throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
1038 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR);
1039 }
1040
1041 /**
1042 *
1043 * @return The name of this attribute
1044 */
1045 public String getName(){
1046 return m_attribute.getName();
1047 }
1048
1049 /**
1050 *
1051 * @return The value of this attribute returned as string
1052 */
1053 public String getValue(){
1054 return m_attribute.getSimpleString();
1055 }
1056
1057 /**
1058 *
1059 * @return The Element node this attribute is attached to
1060 * or null if this attribute is not in use
1061 */
1062 public Element getOwnerElement(){
1063 return m_owner;
1064 }
1065
1066 /**
1067 *
1068 * @return true
1069 */
1070 public boolean getSpecified(){
1071 return true;
1072 }
1073
1074 /**
1075 * @see org.w3c.dom.Attr
1076 *
1077 * @param value Value to set this node to
1078 *
1079 * @throws DOMException
1080 */
1081 public void setValue(String value) throws DOMException
1082 {
1083 throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
1084 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR);
1085 }
1086
1087 public TypeInfo getSchemaTypeInfo() { return null; }
1088
1089 public boolean isId( ) { return false; }
1090
1091 public Object setUserData(String key,
1092 Object data,
1093 UserDataHandler handler) {
1094 return getOwnerDocument().setUserData( key, data, handler);
1095 }
1096
1097 public Object getUserData(String key) {
1098 return getOwnerDocument().getUserData( key);
1099 }
1100
1101 public Object getFeature(String feature, String version) {
1102 return isSupported(feature, version) ? this : null;
1103 }
1104
1105 public boolean isEqualNode(Node arg) {
1106 return arg == this;
1107 }
1108
1109 public String lookupNamespaceURI(String specifiedPrefix) {
1110 return null;
1111 }
1112
1113 public boolean isDefaultNamespace(String namespaceURI) {
1114 return false;
1115 }
1116
1117 public String lookupPrefix(String namespaceURI) {
1118 return null;
1119 }
1120
1121 public boolean isSameNode(Node other) {
1122 // we do not use any wrapper so the answer is obvious
1123 return this == other;
1124 }
1125
1126 public void setTextContent(String textContent)
1127 throws DOMException {
1128 setNodeValue(textContent);
1129 }
1130
1131 public String getTextContent() throws DOMException {
1132 return getNodeValue(); // overriden in some subclasses
1133 }
1134
1135 public short compareDocumentPosition(Node other) throws DOMException {
1136 return 0;
1137 }
1138
1139 public String getBaseURI() {
1140 return null;
1141 }
1142 }
1143
1144 /**
1145 * Get an "extension-element-prefix" property.
1146 * @see <a href="http://www.w3.org/TR/xslt#extension-element">extension-element in XSLT Specification</a>
1147 *
1148 * @param i Index of URI ("extension-element-prefix" property) to get
1149 *
1150 * @return URI at given index ("extension-element-prefix" property)
1151 *
1152 * @throws ArrayIndexOutOfBoundsException
1153 */
1154 public String getExtensionElementPrefix(int i)
1155 throws ArrayIndexOutOfBoundsException
1156 {
1157
1158 if (null == m_ExtensionElementURIs)
1159 throw new ArrayIndexOutOfBoundsException();
1160
1161 return m_ExtensionElementURIs.elementAt(i);
1162 }
1163
1164 /**
1165 * Get the number of "extension-element-prefixes" Strings.
1166 * @see <a href="http://www.w3.org/TR/xslt#extension-element">extension-element in XSLT Specification</a>
1167 *
1168 * @return the number of "extension-element-prefixes" Strings
1169 */
1170 public int getExtensionElementPrefixCount()
1171 {
1172 return (null != m_ExtensionElementURIs)
1173 ? m_ExtensionElementURIs.size() : 0;
1174 }
1175
1176 /**
1177 * Find out if the given "extension-element-prefix" property is defined.
1178 * @see <a href="http://www.w3.org/TR/xslt#extension-element">extension-element in XSLT Specification</a>
1179 *
1180 * @param uri The URI to find
1181 *
1182 * @return True if the given URI is found
1183 */
1184 public boolean containsExtensionElementURI(String uri)
1185 {
1186
1187 if (null == m_ExtensionElementURIs)
1188 return false;
1189
1190 return m_ExtensionElementURIs.contains(uri);
1191 }
1192
1193 /**
1194 * Get an int constant identifying the type of element.
1195 * @see org.apache.xalan.templates.Constants
1196 *
1197 * @return The token ID for this element
1198 */
1199 public int getXSLToken()
1200 {
1201 return Constants.ELEMNAME_LITERALRESULT;
1202 }
1203
1204 /**
1205 * Return the node name.
1206 *
1207 * @return The element's name
1208 */
1209 public String getNodeName()
1210 {
1211
1212 // TODO: Need prefix.
1213 return m_rawName;
1214 }
1215
1216 /**
1217 * The XSLT version as specified by this element.
1218 * @serial
1219 */
1220 private String m_version;
1221
1222 /**
1223 * Set the "version" property.
1224 * @see <a href="http://www.w3.org/TR/xslt#forwards">forwards in XSLT Specification</a>
1225 *
1226 * @param v Version property value to set
1227 */
1228 public void setVersion(String v)
1229 {
1230 m_version = v;
1231 }
1232
1233 /**
1234 * Get the "version" property.
1235 * @see <a href="http://www.w3.org/TR/xslt#forwards">forwards in XSLT Specification</a>
1236 *
1237 * @return Version property value
1238 */
1239 public String getVersion()
1240 {
1241 return m_version;
1242 }
1243
1244 /**
1245 * The "exclude-result-prefixes" property.
1246 * @serial
1247 */
1248 private StringVector m_excludeResultPrefixes;
1249
1250 /**
1251 * Set the "exclude-result-prefixes" property.
1252 * The designation of a namespace as an excluded namespace is
1253 * effective within the subtree of the stylesheet rooted at
1254 * the element bearing the exclude-result-prefixes or
1255 * xsl:exclude-result-prefixes attribute; a subtree rooted
1256 * at an xsl:stylesheet element does not include any stylesheets
1257 * imported or included by children of that xsl:stylesheet element.
1258 * @see <a href="http://www.w3.org/TR/xslt#literal-result-element">literal-result-element in XSLT Specification</a>
1259 *
1260 * @param v vector of prefixes that are resolvable to strings.
1261 */
1262 public void setExcludeResultPrefixes(StringVector v)
1263 {
1264 m_excludeResultPrefixes = v;
1265 }
1266
1267 /**
1268 * Tell if the result namespace decl should be excluded. Should be called before
1269 * namespace aliasing (I think).
1270 *
1271 * @param prefix Prefix of namespace to check
1272 * @param uri URI of namespace to check
1273 *
1274 * @return True if the given namespace should be excluded
1275 *
1276 * @throws TransformerException
1277 */
1278 private boolean excludeResultNSDecl(String prefix, String uri)
1279 throws TransformerException
1280 {
1281
1282 if (null != m_excludeResultPrefixes)
1283 {
1284 return containsExcludeResultPrefix(prefix, uri);
1285 }
1286
1287 return false;
1288 }
1289
1290 /**
1291 * Copy a Literal Result Element into the Result tree, copy the
1292 * non-excluded namespace attributes, copy the attributes not
1293 * of the XSLT namespace, and execute the children of the LRE.
1294 * @see <a href="http://www.w3.org/TR/xslt#literal-result-element">literal-result-element in XSLT Specification</a>
1295 *
1296 * @param transformer non-null reference to the the current transform-time state.
1297 *
1298 * @throws TransformerException
1299 */
1300 public void execute(TransformerImpl transformer)
1301 throws TransformerException
1302 {
1303 SerializationHandler rhandler = transformer.getSerializationHandler();
1304
1305 try
1306 {
1307 if (transformer.getDebug()) {
1308 // flush any buffered pending processing before
1309 // the trace event.
1310 rhandler.flushPending();
1311 transformer.getTraceManager().fireTraceEvent(this);
1312 }
1313
1314 // JJK Bugzilla 3464, test namespace85 -- make sure LRE's
1315 // namespace is asserted even if default, since xsl:element
1316 // may have changed the context.
1317 rhandler.startPrefixMapping(getPrefix(), getNamespace());
1318
1319 // Add namespace declarations.
1320 executeNSDecls(transformer);
1321 rhandler.startElement(getNamespace(), getLocalName(), getRawName());
1322 }
1323 catch (SAXException se)
1324 {
1325 throw new TransformerException(se);
1326 }
1327
1328 /*
1329 * If we make it to here we have done a successful startElement()
1330 * we will do an endElement() call for balance, no matter what happens
1331 * in the middle.
1332 */
1333
1334 // tException remembers if we had an exception "in the middle"
1335 TransformerException tException = null;
1336 try
1337 {
1338
1339 // Process any possible attributes from xsl:use-attribute-sets first
1340 super.execute(transformer);
1341
1342 //xsl:version, excludeResultPrefixes???
1343 // Process the list of avts next
1344 if (null != m_avts)
1345 {
1346 int nAttrs = m_avts.size();
1347
1348 for (int i = (nAttrs - 1); i >= 0; i--)
1349 {
1350 AVT avt = (AVT) m_avts.get(i);
1351 XPathContext xctxt = transformer.getXPathContext();
1352 int sourceNode = xctxt.getCurrentNode();
1353 String stringedValue =
1354 avt.evaluate(xctxt, sourceNode, this);
1355
1356 if (null != stringedValue)
1357 {
1358
1359 // Important Note: I'm not going to check for excluded namespace
1360 // prefixes here. It seems like it's too expensive, and I'm not
1361 // even sure this is right. But I could be wrong, so this needs
1362 // to be tested against other implementations.
1363
1364 rhandler.addAttribute(
1365 avt.getURI(),
1366 avt.getName(),
1367 avt.getRawName(),
1368 "CDATA",
1369 stringedValue, false);
1370 }
1371 } // end for
1372 }
1373
1374 // Now process all the elements in this subtree
1375 // TODO: Process m_extensionElementPrefixes && m_attributeSetsNames
1376 transformer.executeChildTemplates(this, true);
1377 }
1378 catch (TransformerException te)
1379 {
1380 // thrown in finally to prevent original exception consumed by subsequent exceptions
1381 tException = te;
1382 }
1383 catch (SAXException se)
1384 {
1385 tException = new TransformerException(se);
1386 }
1387
1388 try
1389 {
1390 /* we need to do this endElement() to balance the
1391 * successful startElement() call even if
1392 * there was an exception in the middle.
1393 * Otherwise an exception in the middle could cause a system to hang.
1394 */
1395 if (transformer.getDebug()) {
1396 // flush any buffered pending processing before
1397 // the trace event.
1398 //rhandler.flushPending();
1399 transformer.getTraceManager().fireTraceEndEvent(this);
1400 }
1401 rhandler.endElement(getNamespace(), getLocalName(), getRawName());
1402 }
1403 catch (SAXException se)
1404 {
1405 /* we did call endElement(). If thee was an exception
1406 * in the middle throw that one, otherwise if there
1407 * was an exception from endElement() throw that one.
1408 */
1409 if (tException != null)
1410 throw tException;
1411 else
1412 throw new TransformerException(se);
1413 }
1414
1415 /* If an exception was thrown in the middle but not with startElement() or
1416 * or endElement() then its time to let it percolate.
1417 */
1418 if (tException != null)
1419 throw tException;
1420
1421 unexecuteNSDecls(transformer);
1422
1423 // JJK Bugzilla 3464, test namespace85 -- balance explicit start.
1424 try
1425 {
1426 rhandler.endPrefixMapping(getPrefix());
1427 }
1428 catch (SAXException se)
1429 {
1430 throw new TransformerException(se);
1431 }
1432 }
1433
1434 /**
1435 * Compiling templates requires that we be able to list the AVTs
1436 * ADDED 9/5/2000 to support compilation experiment
1437 *
1438 * @return an Enumeration of the literal result attributes associated
1439 * with this element.
1440 */
1441 public Iterator enumerateLiteralResultAttributes()
1442 {
1443 return (null == m_avts) ? null : m_avts.iterator();
1444 }
1445
1446 /**
1447 * Accept a visitor and call the appropriate method
1448 * for this class.
1449 *
1450 * @param visitor The visitor whose appropriate method will be called.
1451 * @return true if the children of the object should be visited.
1452 */
1453 protected boolean accept(XSLTVisitor visitor)
1454 {
1455 return visitor.visitLiteralResultElement(this);
1456 }
1457
1458 /**
1459 * Call the children visitors.
1460 * @param visitor The visitor whose appropriate method will be called.
1461 */
1462 protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs)
1463 {
1464 if (callAttrs && null != m_avts)
1465 {
1466 int nAttrs = m_avts.size();
1467
1468 for (int i = (nAttrs - 1); i >= 0; i--)
1469 {
1470 AVT avt = (AVT) m_avts.get(i);
1471 avt.callVisitors(visitor);
1472 }
1473 }
1474 super.callChildVisitors(visitor, callAttrs);
1475 }
1476
1477 /**
1478 * Throw a DOMException
1479 *
1480 * @param msg key of the error that occured.
1481 */
1482 public void throwDOMException(short code, String msg)
1483 {
1484
1485 String themsg = XSLMessages.createMessage(msg, null);
1486
1487 throw new DOMException(code, themsg);
1488 }
1489
1490 }