KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > xsl > XslWriter


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  * Free SoftwareFoundation, Inc.
23  * 59 Temple Place, Suite 330
24  * Boston, MA 02111-1307 USA
25  *
26  * @author Scott Ferguson
27  */

28
29 package com.caucho.xsl;
30
31 import com.caucho.log.Log;
32 import com.caucho.util.CharBuffer;
33 import com.caucho.util.IntArray;
34 import com.caucho.util.L10N;
35 import com.caucho.vfs.Path;
36 import com.caucho.xml.*;
37 import com.caucho.xpath.Expr;
38 import com.caucho.xpath.ExprEnvironment;
39 import com.caucho.xpath.NamespaceContext;
40 import com.caucho.xpath.XPathException;
41
42 import org.w3c.dom.*;
43 import org.xml.sax.SAXException JavaDoc;
44
45 import java.io.IOException JavaDoc;
46 import java.io.OutputStream JavaDoc;
47 import java.io.Writer JavaDoc;
48 import java.util.ArrayList JavaDoc;
49 import java.util.HashMap JavaDoc;
50 import java.util.Iterator JavaDoc;
51 import java.util.logging.Level JavaDoc;
52 import java.util.logging.Logger JavaDoc;
53
54 /**
55  * Writer stream for generating stylesheet output.
56  *
57  * <p>Because XSL produces an XML tree, XslWriter contains extra
58  * methods for constructing the tree.
59  *
60  * <p>The writer methods, e.g. println, add to the current text node.
61  *
62  * <p>In addition, stylesheets can access variables through getPwd and
63  * getPage.
64  */

65 public class XslWriter extends Writer JavaDoc implements ExtendedLocator {
66   static final Logger JavaDoc log = Log.open(XslWriter.class);
67   static final L10N L = new L10N(XslWriter.class);
68
69   // This is the value Axis wants
70
private final static String JavaDoc XMLNS = "http://www.w3.org/2000/xmlns/";
71
72   private final static XMLWriter ATTR_WRITER = new DOMBuilder();
73
74   private XMLWriter _xmlWriter;
75   
76   String JavaDoc _systemId;
77   String JavaDoc _filename;
78   int _line;
79   int _tailLine;
80
81   private IntArray flags = new IntArray();
82   
83   private CharBuffer _text = new CharBuffer();
84   private String JavaDoc elementName;
85
86   private String JavaDoc _attributeURL;
87   private String JavaDoc _attributePrefix;
88   private String JavaDoc _attributeLocalName;
89   private String JavaDoc _attributeName;
90
91   private ArrayList JavaDoc depends = new ArrayList JavaDoc();
92   private boolean _isCacheable = true;
93   private boolean _disableEscaping;
94
95   private boolean generateLocation;
96
97   private Document _document;
98
99   private StylesheetImpl _stylesheet;
100   private TransformerImpl _transformer;
101
102   private HashMap JavaDoc<String JavaDoc,String JavaDoc> _cdataElements;
103   private boolean isCdata;
104
105   private HashMap JavaDoc<String JavaDoc,String JavaDoc> _namespaces;
106   private ArrayList JavaDoc<String JavaDoc> _topNamespaces;
107   private ArrayList JavaDoc<StackItem> _elementStack;
108   private int _depth;
109
110   private ExtendedLocator _locator = null;
111
112   XslWriter(HashMap JavaDoc env,
113             StylesheetImpl stylesheet,
114             TransformerImpl transformer)
115   {
116     _stylesheet = stylesheet;
117     _transformer = transformer;
118
119     ArrayList JavaDoc<String JavaDoc> cdata = stylesheet.getOutputFormat().getCdataSectionElements();
120     if (cdata != null) {
121       _cdataElements = new HashMap JavaDoc<String JavaDoc,String JavaDoc>();
122       
123       for (int i = 0; i < cdata.size(); i++) {
124         String JavaDoc element = cdata.get(i);
125
126         _cdataElements.put(element, element);
127       }
128     }
129   }
130
131   void init(XMLWriter xmlWriter)
132   {
133     _xmlWriter = xmlWriter;
134     _namespaces = new HashMap JavaDoc<String JavaDoc,String JavaDoc>();
135     _topNamespaces = new ArrayList JavaDoc<String JavaDoc>();
136     _elementStack = new ArrayList JavaDoc<StackItem>();
137
138     _document = null;
139
140     _locator = this;
141     xmlWriter.setDocumentLocator(_locator);
142   }
143
144   public TransformerImpl getTransformer()
145   {
146     return _transformer;
147   }
148
149   /**
150    * Returns true if the generated stylesheet is currently cacheable.
151    */

152   boolean isCacheable()
153   {
154     return _isCacheable;
155   }
156
157   /**
158    * Returns the Path dependency list of the generated stylesheet.
159    */

160   ArrayList JavaDoc getDepends()
161   {
162     return depends;
163   }
164
165   /**
166    * Indicate that the result document is not cacheable.
167    */

168   public void setNotCacheable()
169   {
170     _isCacheable = false;
171   }
172
173   /**
174    * Add a dependency to the result document. When the result is checked
175    * for modification, this path will also be checked.
176    */

177   public void addCacheDepend(Path path)
178   {
179     _transformer.addCacheDepend(path);
180   }
181
182   /**
183    * Implementation function so jsp:decl tags aren't repeated.
184    */

185   public boolean isFlagFirst(int id)
186   {
187     while (flags.size() <= id)
188       flags.add(0);
189
190     int value = flags.get(id);
191     flags.set(id, 1);
192
193     return value == 0;
194   }
195
196   /**
197    * Adds a byte to the current text node.
198    */

199   public void write(int ch)
200   {
201     _text.append((char) ch);
202   }
203   /**
204    * Adds a byte buffer to the current text node.
205    */

206   public void write(byte []buf, int offset, int length)
207   {
208     for (int i = 0; i < length; i++)
209       write(buf[offset + i]);
210   }
211
212   /**
213    * Adds a char buffer to the current text node.
214    */

215   public void write(char []buf, int offset, int length)
216   {
217     _text.append(buf, offset, length);
218   }
219
220   /**
221    * Adds a string to the current text node.
222    */

223   public void print(String JavaDoc string)
224   {
225     if (string == null) {
226       _text.append("null");
227       return;
228     }
229
230     _text.append(string);
231   }
232
233   /**
234    * Adds a boolean to the current text node.
235    */

236   public void print(boolean b)
237   {
238     _text.append(b);
239   }
240
241   /**
242    * Adds a character to the current text node.
243    */

244   public void print(char ch)
245   {
246     _text.append(ch);
247   }
248
249   /**
250    * Adds an integer to the current text node.
251    */

252   public void print(int i)
253   {
254     _text.append(i);
255   }
256
257   /**
258    * Adds an integer to the current text node.
259    */

260   public void print(long l)
261   {
262     _text.append(l);
263   }
264
265   /**
266    * Adds a float to the current text node.
267    */

268   public void print(float f)
269   {
270     _text.append(f);
271   }
272
273   /**
274    * Adds a double to the current text node.
275    */

276   public void print(double d)
277   {
278     _text.append(d);
279   }
280
281   /**
282    * Adds an object to the current text node, converted by
283    * String.valueOf.
284    */

285   public void print(Object JavaDoc o)
286   {
287     _text.append(o);
288   }
289   /**
290    * Adds a newline to the current text node.
291    */

292   public void println()
293   {
294     _text.append('\n');
295     _tailLine++;
296   }
297
298   /**
299    * Adds a boolean to the current text node.
300    */

301   public void println(boolean b)
302   {
303     _text.append(b);
304     println();
305   }
306
307   /**
308    * Adds a string to the current text node.
309    */

310   public void println(String JavaDoc s)
311   {
312     print(s);
313     println();
314   }
315
316   /**
317    * Adds a character to the current text node.
318    */

319   public void println(char ch)
320   {
321     print(ch);
322     println();
323   }
324
325   /**
326    * Adds an integer to the current text node.
327    */

328   public void println(int i)
329   {
330     _text.append(i);
331     println();
332   }
333
334   /**
335    * Adds a long to the current text node.
336    */

337   public void println(long l)
338   {
339     _text.append(l);
340     println();
341   }
342
343   /**
344    * Adds a double to the current text node.
345    */

346   public void println(double d)
347   {
348     _text.append(d);
349     println();
350   }
351
352   /**
353    * Adds a float to the current text node.
354    */

355   public void println(float f)
356   {
357     _text.append(f);
358     println();
359   }
360
361   /**
362    * Adds an object to the current text node, converted by String.valueOf.
363    */

364   public void println(Object JavaDoc o)
365   {
366     _text.append(o);
367     println();
368   }
369
370   /**
371    * flush is meaningless for XslWriter. It's only added to conform to Writer.
372    */

373   public void flush()
374   {
375   }
376
377   public void close()
378     throws IOException JavaDoc
379   {
380     try {
381       for (int i = 0; i < _topNamespaces.size(); i++) {
382         String JavaDoc topPrefix = _topNamespaces.get(i);
383         String JavaDoc topUrl = _namespaces.get(topPrefix);
384
385         if (topPrefix.equals(""))
386       _xmlWriter.endPrefixMapping(null);
387         else
388       _xmlWriter.endPrefixMapping(topPrefix);
389       }
390
391       popText();
392       _xmlWriter.endDocument();
393     } catch (SAXException JavaDoc e) {
394       throw new IOException JavaDoc(e.toString());
395     }
396   }
397
398   public boolean getDisableEscaping()
399   {
400     return _disableEscaping;
401   }
402   
403   public boolean disableEscaping(boolean disable)
404     throws IOException JavaDoc, SAXException JavaDoc
405   {
406     if (disable != _disableEscaping) {
407       popText();
408       _xmlWriter.setEscapeText(! disable);
409     }
410
411     boolean old = _disableEscaping;
412     _disableEscaping = disable;
413
414     return old;
415   }
416
417   public void setLocation(String JavaDoc systemId, String JavaDoc filename, int line)
418     throws IOException JavaDoc, SAXException JavaDoc
419   {
420     // Don't need to pop the text if the line # matches
421
if (filename == null || ! filename.equals(_filename) ||
422         line != _tailLine)
423       popText();
424
425     _systemId = systemId;
426     _filename = filename;
427     _line = line;
428     _tailLine = line;
429   }
430
431   /**
432    * Adds a new element to the current node, making the new element the
433    * current node.
434    *
435    * <p>Each pushElement should be matched by a popElement.
436    *
437    * @param name name of the element
438    */

439   public void pushElement(String JavaDoc name)
440    throws IOException JavaDoc, SAXException JavaDoc
441   {
442     popText();
443
444     String JavaDoc local;
445     int p = name.lastIndexOf(':');
446     if (p > 0)
447       local = name.substring(p + 1);
448     else
449       local = name;
450     
451     startElement(null, null, local, name);
452   }
453
454   /**
455    * Adds a new element to the current node, making the new element the
456    * current node.
457    *
458    * <p>Each pushElement should be matched by a popElement.
459    *
460    * @param name name of the element
461    * @param namespace namespace context
462    */

463   public void pushElement(String JavaDoc name, NamespaceContext namespace)
464    throws IOException JavaDoc, SAXException JavaDoc
465   {
466     popText();
467
468     // Look up the proper namespace for the element.
469
int p = name.indexOf(':');
470     if (p <= 0) {
471       startElement(null, null, name, name);
472       return;
473     }
474
475     String JavaDoc prefix = name.substring(0, p);
476     String JavaDoc url = namespace.find(namespace, prefix);
477     
478     if (url != null)
479       startElement(url, prefix, name.substring(p + 1), name);
480     else
481       startElement(null, null, name, name);
482   }
483
484   /**
485    * Adds a new element to the current node, making the new element the
486    * current node.
487    *
488    * <p>Each pushElement should be matched by a popElement.
489    *
490    * @param name name of the element
491    * @param url namespace url
492    */

493   public void pushElementNs(String JavaDoc name, String JavaDoc url)
494    throws IOException JavaDoc, SAXException JavaDoc
495   {
496     popText();
497     
498     // Look up the proper namespace for the element.
499
int p = name.indexOf(':');
500     if (p <= 0) {
501       startElement(url, "", name, name);
502       return;
503     }
504
505     String JavaDoc prefix = name.substring(0, p);
506     String JavaDoc local = name.substring(p + 1);
507
508     startElement(url, prefix, local, name);
509   }
510
511   /**
512    * Adds a namespace-aware element to the current node, making the
513    * new element the current node.
514    *
515    * <p>Each pushElement should be matched by a popElement.
516    *
517    * @param prefix the prefix of the element name, e.g. xsl
518    * @param local the local part of the element name, e.g. template
519    * @param url the namespace url, e.g. http://www.xml.org/...
520    */

521   public void pushElement(String JavaDoc url, String JavaDoc prefix, String JavaDoc local, String JavaDoc name)
522    throws IOException JavaDoc, SAXException JavaDoc
523   {
524     popText();
525
526     /*
527     if (url != null && url.startsWith("quote:"))
528       url = url.substring(6);
529     */

530     
531     startElement(url, prefix, local, name);
532   }
533
534   /**
535    * Adds a new attribute with the given name to the current node, making
536    * the attribute the current node.
537    */

538   public XMLWriter pushAttribute(String JavaDoc name)
539     throws IOException JavaDoc, SAXException JavaDoc
540   {
541     popText();
542
543     XMLWriter oldWriter = _xmlWriter;
544     _xmlWriter = ATTR_WRITER;
545     
546     _attributeURL = null;
547     _attributePrefix = null;
548     _attributeLocalName = null;
549     _attributeName = name;
550
551     return oldWriter;
552   }
553
554   /**
555    * Adds a new attribute with the given name to the current node, making
556    * the attribute the current node.
557    */

558   public XMLWriter pushAttribute(String JavaDoc name, NamespaceContext namespace)
559    throws IOException JavaDoc, SAXException JavaDoc
560   {
561     popText();
562
563     XMLWriter oldWriter = _xmlWriter;
564     _xmlWriter = ATTR_WRITER;
565     
566     // Look up the proper namespace for the element.
567
int p = name.indexOf(':');
568     String JavaDoc prefix = null;
569     if (p > 0)
570       prefix = name.substring(0, p);
571     String JavaDoc url = namespace.find(namespace, prefix);
572     Attr attr;
573     
574     if (url != null) {
575       _attributeURL = url;
576       _attributePrefix = prefix;
577       _attributeLocalName = name.substring(p + 1);
578       _attributeName = name;
579     }
580     else {
581       _attributeURL = null;
582       _attributePrefix = null;
583       _attributeLocalName = null;
584       _attributeName = name;
585     }
586
587     return oldWriter;
588   }
589
590   /**
591    * Adds a new attribute to the current node, making the new attribute the
592    * current node.
593    *
594    * <p>Each pushAttributeNs should be matched by a popAttribute.
595    *
596    * @param name name of the element
597    * @param url namespace url
598    */

599   public XMLWriter pushAttributeNs(String JavaDoc name, String JavaDoc url)
600    throws IOException JavaDoc, SAXException JavaDoc
601   {
602     popText();
603
604     XMLWriter oldWriter = _xmlWriter;
605     _xmlWriter = ATTR_WRITER;
606     
607     Attr attr;
608
609     // Look up the proper namespace for the element.
610
int p = name.indexOf(':');
611     String JavaDoc prefix = null;
612     String JavaDoc local = name;
613     if (p > 0) {
614       prefix = name.substring(0, p);
615       local = name.substring(p + 1);
616     }
617
618     _attributeURL = url;
619     _attributePrefix = prefix;
620     _attributeLocalName = local;
621     _attributeName = name;
622
623     return oldWriter;
624   }
625
626   /**
627    * Adds a namespace-aware attribute to the current node, making the
628    * new attribute the current node.
629    *
630    * <p>Each pushAttribute should be matched by a popAttribute.
631    *
632    * @param prefix the prefix of the element name, e.g. xsl
633    * @param local the local part of the element name, e.g. template
634    * @param url the namespace url, e.g. http://www.xml.org/...
635    */

636   public XMLWriter pushAttribute(String JavaDoc prefix, String JavaDoc local, String JavaDoc url)
637     throws IOException JavaDoc, SAXException JavaDoc
638   {
639     popText();
640
641     XMLWriter oldWriter = _xmlWriter;
642     _xmlWriter = ATTR_WRITER;
643     
644     /*
645     if (url != null && url.startsWith("quote:"))
646       url = url.substring(6);
647     */

648     
649     _attributeURL = url;
650     _attributePrefix = prefix;
651     _attributeLocalName = local;
652     
653     if (prefix != null && ! prefix.equals(""))
654       _attributeName = prefix + ":" + local;
655     else
656       _attributeName = local;
657
658     return oldWriter;
659   }
660
661   /**
662    * Adds a namespace-aware attribute to the current node, making the
663    * new attribute the current node.
664    *
665    * <p>Each pushAttribute should be matched by a popAttribute.
666    *
667    * @param prefix the prefix of the element name, e.g. xsl
668    * @param local the local part of the element name, e.g. template
669    * @param url the namespace url, e.g. http://www.xml.org/...
670    */

671   public void setAttribute(String JavaDoc prefix, String JavaDoc local, String JavaDoc url,
672                String JavaDoc value)
673     throws IOException JavaDoc, SAXException JavaDoc
674   {
675     popText();
676
677     /*
678     if (url != null && url.startsWith("quote:"))
679       url = url.substring(6);
680     */

681
682     String JavaDoc attributeName;
683     if (prefix != null && ! prefix.equals(""))
684       attributeName = prefix + ":" + local;
685     else
686       attributeName = local;
687     
688     attribute(url, prefix, local, attributeName, value);
689   }
690
691   /**
692    * Adds a new attribute with the given name to the current node, making
693    * the attribute the current node.
694    */

695   public void setAttribute(String JavaDoc name, NamespaceContext namespace, String JavaDoc value)
696    throws IOException JavaDoc, SAXException JavaDoc
697   {
698     popText();
699     
700     // Look up the proper namespace for the element.
701
int p = name.indexOf(':');
702     String JavaDoc prefix = null;
703     if (p > 0)
704       prefix = name.substring(0, p);
705     String JavaDoc url = namespace.find(namespace, prefix);
706     Attr attr;
707     
708     if (url != null) {
709       attribute(url, prefix, name.substring(p + 1), name, value);
710     }
711     else {
712       attribute(null, null, null, name, value);
713     }
714   }
715
716   /**
717    * Sets the attribute value to the current text, and sets the current node
718    * to the parent.
719    */

720   public void popAttribute(XMLWriter writer)
721    throws IOException JavaDoc, SAXException JavaDoc
722   {
723     _xmlWriter = writer;
724     
725     attribute(_attributeURL, _attributePrefix,
726               _attributeLocalName, _attributeName,
727               _text.toString());
728     
729     _text.clear();
730     _attributeName = null;
731   }
732
733   /**
734    * Directly sets an attribute with a value.
735    */

736   public void setAttribute(String JavaDoc name, String JavaDoc value)
737     throws IOException JavaDoc, SAXException JavaDoc
738   {
739     attribute(null, null, name, name, value);
740   }
741
742   /**
743    * Copies the node without attributes or children.
744    */

745   public void pushCopy(Node copyNode)
746     throws IOException JavaDoc, SAXException JavaDoc
747   {
748     popText();
749
750     switch (copyNode.getNodeType()) {
751     case Node.ATTRIBUTE_NODE:
752       QAbstractNode oldNode = (QAbstractNode) copyNode;
753       attribute(oldNode.getNamespaceURI(),
754                 oldNode.getPrefix(),
755                 oldNode.getLocalName(),
756                 oldNode.getNodeName(),
757                 oldNode.getNodeValue());
758       break;
759
760     case Node.DOCUMENT_NODE:
761       return;
762
763     case Node.ELEMENT_NODE:
764       QElement oldElt = (QElement) copyNode;
765
766       /*
767       String oldSystemId = _systemId;
768       String oldFilename = _filename;
769       int oldLine = _line;
770
771       _systemId = oldElt.getBaseURI();
772       _filename = oldElt.getFilename();
773       _line = oldElt.getLine();
774
775       if (generateLocation)
776         _xmlWriter.setLocation(.getFilename(), oldElt.getLine(), 0);
777       */

778
779       startElement(oldElt.getNamespaceURI(),
780                    oldElt.getPrefix(),
781                    oldElt.getLocalName(),
782                    oldElt.getNodeName());
783
784       /*
785       _systemId = oldSystemId;
786       _filename = oldFilename;
787       _line = oldLine;
788       */

789       break;
790
791     case Node.COMMENT_NODE:
792       _xmlWriter.comment(((Comment) copyNode).getData());
793       break;
794
795     case Node.TEXT_NODE:
796       /*
797       if (generateLocation)
798         _xmlWriter.setLocation(((QAbstractNode) copyNode).getFilename(),
799                               ((QAbstractNode) copyNode).getLine(),
800                               0);
801       */

802       _text.append(((Text) copyNode).getData());
803       break;
804
805     case Node.PROCESSING_INSTRUCTION_NODE:
806       ProcessingInstruction oldPi = (ProcessingInstruction) copyNode;
807
808       _xmlWriter.processingInstruction(oldPi.getNodeName(), oldPi.getNodeValue());
809       break;
810     }
811   }
812
813   /**
814    * Pops the copy.
815    */

816   public void popCopy(Node copyNode)
817    throws IOException JavaDoc, SAXException JavaDoc
818   {
819     if (copyNode.getNodeType() == Node.ELEMENT_NODE) {
820       popText();
821       popElement();
822     }
823   }
824
825   public void pushPi()
826     throws IOException JavaDoc, SAXException JavaDoc
827   {
828     popText();
829   }
830   /**
831    * Sets the PI data to the current text, and sets the current node
832    * to the parent.
833    */

834   public void popPi(String JavaDoc name)
835    throws IOException JavaDoc, SAXException JavaDoc
836   {
837     _xmlWriter.processingInstruction(name, _text.toString());
838     _text.clear();
839   }
840
841   /**
842    * Adds an empty comment to the current node, making
843    * the attribute the current node.
844    */

845   public void pushComment()
846    throws IOException JavaDoc, SAXException JavaDoc
847   {
848     popText();
849   }
850
851   /**
852    * Sets the comment data to the current text, and sets the current
853    * to the the parent.
854    */

855   public void popComment()
856    throws IOException JavaDoc, SAXException JavaDoc
857   {
858     _xmlWriter.comment(_text.toString());
859     
860     _text.clear();
861   }
862
863   /**
864    * Starts a fragment. The fragment becomes the current node.
865    */

866   public XMLWriter pushFragment()
867    throws IOException JavaDoc, SAXException JavaDoc
868   {
869     popText();
870
871     DOMBuilder domBuilder = new DOMBuilder();
872
873     if (_document == null)
874       _document = Xml.createDocument();
875     domBuilder.init(_document.createDocumentFragment());
876     domBuilder.setDocumentLocator(_locator);
877
878     XMLWriter oldWriter = _xmlWriter;
879     _xmlWriter = domBuilder;
880
881     return oldWriter;
882   }
883
884   /**
885    * Returns the generated fragment. The current node does not contain
886    * the new fragment.
887    *
888    * @return the generated fragment.
889    */

890   public Node popFragment(XMLWriter oldWriter)
891    throws IOException JavaDoc, SAXException JavaDoc
892   {
893     popText();
894
895     DOMBuilder domBuilder = (DOMBuilder) _xmlWriter;
896
897     _xmlWriter = oldWriter;
898
899     domBuilder.endDocument();
900     Node node = domBuilder.getNode();
901
902     return node;
903   }
904
905   /**
906    * Adds a the contents of the node to the current node.
907    *
908    * @param node node to print
909    */

910   public void valueOf(Object JavaDoc node)
911    throws IOException JavaDoc, SAXException JavaDoc
912   {
913     if (node == null)
914       return;
915     else if (node instanceof Element || node instanceof DocumentFragment) {
916       Node elt = (Node) node;
917       for (Node child = elt.getFirstChild();
918        child != null;
919        child = child.getNextSibling()) {
920     elementValueOf(child);
921       }
922     }
923     else if (node instanceof Text) {
924       String JavaDoc data = ((Text) node).getNodeValue();
925       for (int i = 0; i < data.length(); i++) {
926     if (! XmlChar.isWhitespace(data.charAt(i))) {
927       print(data);
928       return;
929     }
930       }
931       /*
932       if (! _stylesheet.stripSpaces(((Node) node).getParentNode()))
933       */

934       print(data);
935     }
936     else if (node instanceof Node) {
937       print(((QAbstractNode) node).getNodeValue());
938     }
939     else if (node instanceof NodeList) {
940       NodeList list = (NodeList) node;
941       Node value = list.item(0);
942
943       if (value != null)
944         valueOf(value);
945     }
946     else if (node instanceof ArrayList JavaDoc) {
947       ArrayList JavaDoc list = (ArrayList JavaDoc) node;
948       if (list.size() > 0)
949         valueOf(list.get(0));
950     }
951     else if (node instanceof Iterator JavaDoc) {
952       Iterator JavaDoc list = (Iterator JavaDoc) node;
953       valueOf(list.next());
954     }
955     else if (node instanceof Double JavaDoc) {
956       Double JavaDoc d = (Double JavaDoc) node;
957       double dValue = d.doubleValue();
958
959       if ((int) dValue == dValue)
960     print((int) dValue);
961       else
962     print(dValue);
963     }
964     else
965       print(node);
966   }
967
968   /**
969    * Adds a the contents of the node to the current node.
970    *
971    * @param node node to print
972    */

973   private void elementValueOf(Node node)
974    throws IOException JavaDoc, SAXException JavaDoc
975   {
976     if (node == null)
977       return;
978     else if (node instanceof Element) {
979       Element elt = (Element) node;
980       for (Node child = elt.getFirstChild();
981        child != null;
982        child = child.getNextSibling()) {
983     elementValueOf(child);
984       }
985     }
986     else if (node instanceof Text) {
987       String JavaDoc data = ((Text) node).getNodeValue();
988       for (int i = 0; i < data.length(); i++) {
989     if (! XmlChar.isWhitespace(data.charAt(i))) {
990       print(data);
991       return;
992     }
993       }
994       /*
995       if (! _stylesheet.stripSpaces(node.getParentNode()))
996       */

997       print(data);
998     }
999   }
1000
1001  /**
1002   * Adds a deep copy of the node to the current node.
1003   *
1004   * @param XPath node to be copied to the destination.
1005   */

1006  public void copyOf(Object JavaDoc value)
1007    throws IOException JavaDoc, SAXException JavaDoc, XPathException
1008  {
1009    popText();
1010
1011    if (value instanceof NodeList) {
1012      NodeList list = (NodeList) value;
1013
1014      int length = list.getLength();
1015      for (int i = 0; i < length; i++) {
1016    Node child = list.item(i);
1017
1018    copyOf(child);
1019      }
1020    }
1021    else if (value instanceof ArrayList JavaDoc) {
1022      ArrayList JavaDoc list = (ArrayList JavaDoc) value;
1023
1024      for (int i = 0; i < list.size(); i++) {
1025    Node child = (Node) list.get(i);
1026
1027    copyOf(child);
1028      }
1029    }
1030    else if (value instanceof Iterator JavaDoc) {
1031      Iterator JavaDoc iter = (Iterator JavaDoc) value;
1032
1033      while (iter.hasNext()) {
1034    Node child = (Node) iter.next();
1035
1036    copyOf(child);
1037      }
1038    }
1039    else if (value instanceof Attr) {
1040      Attr child = (Attr) value;
1041
1042      attribute(child.getNamespaceURI(),
1043                child.getPrefix(),
1044                child.getLocalName(),
1045                child.getNodeName(),
1046                child.getNodeValue());
1047    }
1048    else if (value instanceof QElement) {
1049      QElement child = (QElement) value;
1050
1051      String JavaDoc oldSystemId = _systemId;
1052      String JavaDoc oldFilename = _filename;
1053      int oldLine = _line;
1054
1055      _systemId = child.getBaseURI();
1056      _filename = child.getFilename();
1057      _line = child.getLine();
1058
1059      startElement(child.getNamespaceURI(),
1060                   child.getPrefix(),
1061                   child.getLocalName(),
1062                   child.getNodeName());
1063      Node subNode = child.getFirstAttribute();
1064      for (; subNode != null; subNode = subNode.getNextSibling()) {
1065        QAttr attr = (QAttr) subNode;
1066        
1067        attribute(attr.getNamespaceURI(),
1068                  attr.getPrefix(),
1069                  attr.getLocalName(),
1070                  attr.getNodeName(),
1071                  attr.getNodeValue());
1072      }
1073      
1074      for (subNode = child.getFirstChild();
1075           subNode != null;
1076           subNode = subNode.getNextSibling()) {
1077        copyOf(subNode);
1078      }
1079
1080      popElement();
1081
1082      _systemId = oldSystemId;
1083      _filename = oldFilename;
1084      _line = oldLine;
1085    }
1086    else if (value instanceof DocumentFragment) {
1087      for (Node subNode = ((Node) value).getFirstChild();
1088           subNode != null;
1089           subNode = subNode.getNextSibling()) {
1090        copyOf(subNode);
1091      }
1092    }
1093    else if (value instanceof Text) {
1094      Text child = (Text) value;
1095
1096      _text.append(child.getNodeValue());
1097    }
1098    else if (value instanceof Comment) {
1099      Comment child = (Comment) value;
1100
1101      _xmlWriter.comment(child.getNodeValue());
1102    }
1103    else if (value instanceof ProcessingInstruction) {
1104      ProcessingInstruction pi = (ProcessingInstruction) value;
1105      
1106      _xmlWriter.processingInstruction(pi.getNodeName(),
1107                       pi.getNodeValue());
1108    }
1109    else if (value instanceof EntityReference) {
1110      EntityReference child = (EntityReference) value;
1111
1112      _text.append("&" + child.getNodeName() + ";");
1113    }
1114    else if (value instanceof Node) {
1115      Node child = (Node) value;
1116
1117      _text.append(child.getNodeValue());
1118    }
1119    else {
1120      print(Expr.toString(value));
1121    }
1122  }
1123
1124  public void addNamespace(String JavaDoc prefix, String JavaDoc url)
1125  {
1126    /*
1127    if (url.startsWith("quote:"))
1128      url = url.substring(6);
1129    */

1130    if (! url.equals("")) {
1131      _namespaces.put(prefix, url);
1132
1133      _topNamespaces.add(prefix);
1134    }
1135  }
1136
1137  void startElement(String JavaDoc url, String JavaDoc prefix, String JavaDoc local, String JavaDoc qName)
1138    throws IOException JavaDoc, SAXException JavaDoc
1139  {
1140    if (_attributeName != null)
1141      throw error(L.l("element `{0}' is not allowed inside attribute `{1}'. xsl:attribute must contain text only.", qName, _attributeName));
1142    popText();
1143
1144    StackItem item = null;
1145    if (_elementStack.size() <= _depth) {
1146      item = new StackItem();
1147      _elementStack.add(item);
1148    }
1149    else
1150      item = _elementStack.get(_depth);
1151
1152    item.init(url, prefix, local, qName, isCdata);
1153
1154    if (_cdataElements != null && _cdataElements.get(qName) != null)
1155      isCdata = true;
1156    
1157    _depth++;
1158
1159    _xmlWriter.startElement(url, local, qName);
1160
1161    // Initialize top-level namespaces
1162
if (_depth == 1) {
1163      for (int i = 0; i < _topNamespaces.size(); i++) {
1164        String JavaDoc topPrefix = _topNamespaces.get(i);
1165        String JavaDoc topUrl = _namespaces.get(topPrefix);
1166
1167        if (topPrefix.equals("")) {
1168      _xmlWriter.startPrefixMapping(null, topUrl);
1169          _xmlWriter.attribute(XMLNS, null, "xmlns", topUrl);
1170    }
1171        else {
1172      _xmlWriter.startPrefixMapping(topPrefix, topUrl);
1173          _xmlWriter.attribute(XMLNS, topPrefix, "xmlns:" + topPrefix, topUrl);
1174    }
1175      }
1176    }
1177
1178    if (url == null)
1179      return;
1180
1181    bindNamespace(prefix, url);
1182  }
1183
1184  public void popElement()
1185    throws IOException JavaDoc, SAXException JavaDoc
1186  {
1187    popText();
1188    _depth--;
1189
1190    StackItem item = _elementStack.get(_depth);
1191    
1192    try{
1193      _xmlWriter.endElement(item.getNamespace(),
1194                           item.getLocalName(),
1195                           item.getName());
1196
1197      // If this element bound namespaces, pop the old values
1198
for (int i = 0; i < item.nsSize(); i++) {
1199        String JavaDoc oldPrefix = item.getNSPrefix(i);
1200        String JavaDoc oldUrl = item.getNSUrl(i);
1201
1202        if (oldUrl == null)
1203          _namespaces.remove(oldPrefix);
1204        else
1205          _namespaces.put(oldPrefix, oldUrl);
1206
1207    _xmlWriter.endPrefixMapping(oldPrefix);
1208      }
1209
1210      isCdata = item.getCdata();
1211    } catch (Throwable JavaDoc e) {
1212      log.log(Level.FINE, e.toString(), e);
1213    }
1214  }
1215
1216  /**
1217   * Sends the attribute to the output
1218   *
1219   * @param url the namespace for the attribute name
1220   * @param prefix the prefix for the attribute name
1221   * @param local the local attribute name
1222   * @param qName the full qualified name
1223   * @param value the attribute's value
1224   */

1225  public void attribute(String JavaDoc url, String JavaDoc prefix, String JavaDoc local,
1226            String JavaDoc qName, String JavaDoc value)
1227    throws IOException JavaDoc, SAXException JavaDoc
1228  {
1229    if (qName.startsWith("xmlns:"))
1230      bindNamespace(qName.substring("xmlns:".length()), value);
1231    else if (qName.equals("xmlns"))
1232      bindNamespace(null, value);
1233    else {
1234      _xmlWriter.attribute(url, local, qName, value);
1235
1236      // null namespace binding doesn't add binding
1237
if (url != null && ! url.equals("") && ! prefix.equals(""))
1238        bindNamespace(prefix, url);
1239    }
1240  }
1241
1242  /**
1243   * Sends the attribute to the output
1244   *
1245   * @param url the namespace for the attribute name
1246   * @param prefix the prefix for the attribute name
1247   * @param local the local attribute name
1248   * @param qName the full qualified name
1249   * @param value the attribute's value
1250   */

1251  public void attribute(String JavaDoc qName, String JavaDoc value)
1252    throws IOException JavaDoc, SAXException JavaDoc
1253  {
1254    _xmlWriter.attribute(null, null, qName, value);
1255  }
1256
1257  public void bindNamespace(String JavaDoc prefix, String JavaDoc url)
1258    throws IOException JavaDoc, SAXException JavaDoc
1259  {
1260    String JavaDoc oldUrl = _namespaces.get(prefix);
1261
1262    // If the namespace matches, return
1263
if (oldUrl == null && url.equals("") ||
1264        oldUrl != null && url.equals(oldUrl))
1265      return;
1266
1267    // Send the namespace declaration to the writer
1268
if (prefix != null) {
1269      _xmlWriter.startPrefixMapping(prefix, url);
1270      _xmlWriter.attribute(XMLNS, prefix, "xmlns:" + prefix, url);
1271      _namespaces.put(prefix, url);
1272    }
1273    else {
1274      _xmlWriter.startPrefixMapping(null, url);
1275      _xmlWriter.attribute(XMLNS, null, "xmlns", url);
1276      _namespaces.put(null, url);
1277    }
1278
1279    StackItem item = _elementStack.get(_depth - 1);
1280    item.addNamespace(prefix, oldUrl);
1281  }
1282
1283  /**
1284   * Pop the accumulated text to the DOM.
1285   */

1286  public void popText()
1287    throws IOException JavaDoc, SAXException JavaDoc
1288  {
1289    if (_xmlWriter == ATTR_WRITER)
1290      return;
1291    
1292    Text textNode = null;
1293    
1294    if (_text.length() == 0)
1295      return;
1296    
1297    if (_filename != null)
1298      _line = _tailLine;
1299
1300    if (isCdata)
1301      _xmlWriter.cdata(_text.getBuffer(), 0, _text.getLength());
1302    else
1303      _xmlWriter.text(_text.getBuffer(), 0, _text.getLength());
1304    
1305    _text.clear();
1306  }
1307
1308  /**
1309   * Returns the attribute with the given name.
1310   */

1311  public Object JavaDoc getProperty(String JavaDoc name)
1312  {
1313    return _transformer.getProperty(name);
1314  }
1315
1316  /**
1317   * Sets the attribute with the given name.
1318   */

1319  public void setProperty(String JavaDoc name, Object JavaDoc value)
1320  {
1321    _transformer.setProperty(name, value);
1322  }
1323
1324  /**
1325   * removes the attribute with the given name.
1326   */

1327  public void removeProperty(String JavaDoc name)
1328  {
1329  }
1330
1331  /**
1332   * Lists the names of all the attributes.
1333   */

1334  public Iterator JavaDoc getPropertyNames()
1335  {
1336    return null;
1337  }
1338
1339  public Object JavaDoc getParameter(String JavaDoc name)
1340  {
1341    return _transformer.getParameter(name);
1342  }
1343
1344  public Path getPwd()
1345  {
1346    return (Path) getProperty("caucho.pwd");
1347  }
1348
1349  public OutputStream JavaDoc openWrite(ExprEnvironment env, String JavaDoc href)
1350    throws IOException JavaDoc
1351  {
1352    if (_xmlWriter instanceof XmlPrinter) {
1353      XmlPrinter printer = (XmlPrinter) _xmlWriter;
1354
1355      Path path = printer.getPath();
1356
1357      if (path != null) {
1358    Path dst = path.getParent().lookup(href);
1359    dst.getParent().mkdirs();
1360    
1361        return dst.openWrite();
1362      }
1363    }
1364    
1365    Path stylesheetPath = env.getStylesheetEnv().getPath();
1366    
1367    return stylesheetPath.getParent().lookup(href).openWrite();
1368  }
1369
1370  public XslWriter openResultDocument(OutputStream JavaDoc os)
1371    throws IOException JavaDoc, SAXException JavaDoc
1372  {
1373    XMLWriter writer = new XmlPrinter(os);
1374    XslWriter out = new XslWriter(null, _stylesheet, _transformer);
1375    out.init(writer);
1376
1377    writer.startDocument();
1378
1379    return out;
1380  }
1381
1382  /**
1383   * @deprecated
1384   */

1385  public javax.servlet.jsp.PageContext JavaDoc getPage()
1386  {
1387    return (javax.servlet.jsp.PageContext JavaDoc) getProperty("caucho.page.context");
1388  }
1389
1390  private IOException JavaDoc error(String JavaDoc message)
1391  {
1392    if (_filename != null)
1393      return new IOException JavaDoc(_filename + ":" + _line + ": " + message);
1394    else
1395      return new IOException JavaDoc(message);
1396  }
1397  
1398  public String JavaDoc getSystemId()
1399  {
1400    if (_systemId != null)
1401      return _systemId;
1402    else
1403      return _filename;
1404  }
1405    
1406  public String JavaDoc getFilename()
1407  {
1408    if (_filename != null)
1409      return _filename;
1410    else
1411      return _systemId;
1412  }
1413    
1414  public String JavaDoc getPublicId()
1415  {
1416    return null;
1417  }
1418
1419  public int getLineNumber()
1420  {
1421    return _line;
1422  }
1423
1424  public int getColumnNumber()
1425  {
1426    return 0;
1427  }
1428
1429  static class StackItem {
1430    String JavaDoc _url;
1431    String JavaDoc _prefix;
1432    String JavaDoc _local;
1433    String JavaDoc _qName;
1434    boolean _isCdata;
1435
1436    ArrayList JavaDoc<String JavaDoc> _nsPrefixes;
1437    ArrayList JavaDoc<String JavaDoc> _nsUrls;
1438
1439    void clear()
1440    {
1441    }
1442
1443    void init(String JavaDoc url, String JavaDoc prefix, String JavaDoc local, String JavaDoc qName,
1444              boolean isCdata)
1445    {
1446      if (_nsPrefixes != null) {
1447        _nsPrefixes.clear();
1448        _nsUrls.clear();
1449      }
1450
1451      _url = url;
1452      _prefix = prefix;
1453      _local = local;
1454      _qName = qName;
1455
1456      _isCdata = isCdata;
1457    }
1458
1459    String JavaDoc getNamespace()
1460    {
1461      return _url;
1462    }
1463
1464    String JavaDoc getPrefix()
1465    {
1466      return _prefix;
1467    }
1468
1469    String JavaDoc getLocalName()
1470    {
1471      return _local;
1472    }
1473
1474    String JavaDoc getName()
1475    {
1476      return _qName;
1477    }
1478
1479    boolean getCdata()
1480    {
1481      return _isCdata;
1482    }
1483
1484    int nsSize()
1485    {
1486      return _nsPrefixes == null ? 0 : _nsPrefixes.size();
1487    }
1488
1489    String JavaDoc getNSPrefix(int i)
1490    {
1491      return _nsPrefixes.get(i);
1492    }
1493
1494    String JavaDoc getNSUrl(int i)
1495    {
1496      return _nsUrls.get(i);
1497    }
1498
1499    void addNamespace(String JavaDoc prefix, String JavaDoc oldUrl)
1500    {
1501      if (_nsPrefixes == null) {
1502        _nsPrefixes = new ArrayList JavaDoc<String JavaDoc>();
1503        _nsUrls = new ArrayList JavaDoc<String JavaDoc>();
1504      }
1505
1506      _nsPrefixes.add(prefix);
1507      _nsUrls.add(oldUrl);
1508    }
1509  }
1510}
1511
Popular Tags