KickJava   Java API By Example, From Geeks To Geeks.

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


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  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.xsl;
31
32 import com.caucho.java.LineMap;
33 import com.caucho.log.Log;
34 import com.caucho.util.CharBuffer;
35 import com.caucho.util.IntArray;
36 import com.caucho.vfs.Path;
37 import com.caucho.xml.CauchoNode;
38 import com.caucho.xml.QAbstractNode;
39 import com.caucho.xml.QElement;
40 import com.caucho.xml.XMLWriter;
41 import com.caucho.xml.XmlChar;
42 import com.caucho.xml.XmlUtil;
43 import com.caucho.xpath.Env;
44 import com.caucho.xpath.Expr;
45 import com.caucho.xpath.StylesheetEnv;
46 import com.caucho.xpath.XPath;
47 import com.caucho.xpath.XPathException;
48 import com.caucho.xpath.XPathFun;
49 import com.caucho.xpath.pattern.AbstractPattern;
50 import com.caucho.xpath.pattern.NodeIterator;
51 import com.caucho.xsl.fun.DocumentFun;
52 import com.caucho.xsl.fun.ExtensionElementFun;
53 import com.caucho.xsl.fun.ExtensionFunctionFun;
54 import com.caucho.xsl.fun.SystemPropertyFun;
55 import com.caucho.xsl.fun.UnparsedEntityFun;
56
57 import org.w3c.dom.Document JavaDoc;
58 import org.w3c.dom.Element JavaDoc;
59 import org.w3c.dom.NamedNodeMap JavaDoc;
60 import org.w3c.dom.Node JavaDoc;
61 import org.w3c.dom.Text JavaDoc;
62 import org.xml.sax.SAXException JavaDoc;
63
64 import javax.xml.transform.TransformerException JavaDoc;
65 import java.io.IOException JavaDoc;
66 import java.util.ArrayList JavaDoc;
67 import java.util.Comparator JavaDoc;
68 import java.util.HashMap JavaDoc;
69 import java.util.Iterator JavaDoc;
70 import java.util.Locale JavaDoc;
71 import java.util.logging.Logger JavaDoc;
72
73 /**
74  * Implementation base class for stylesheets. It is made public only
75  * because generated Java and JavaScript classes need to access these
76  * routines.
77  */

78 public class StylesheetImpl extends AbstractStylesheet {
79   static final Logger JavaDoc log = Log.open(StylesheetImpl.class);
80
81   public char []text; // static buffer of the text nodes
82

83   protected HashMap JavaDoc templates;
84   HashMap JavaDoc<String JavaDoc,XPathFun> _funs = new HashMap JavaDoc<String JavaDoc,XPathFun>();
85
86   private HashMap JavaDoc<String JavaDoc,String JavaDoc> _preserve;
87   private HashMap JavaDoc<String JavaDoc,String JavaDoc> _strip;
88   private HashMap JavaDoc<String JavaDoc,String JavaDoc> _preservePrefix;
89   private HashMap JavaDoc<String JavaDoc,String JavaDoc> _stripPrefix;
90   private HashMap JavaDoc<String JavaDoc,Object JavaDoc> _properties = new HashMap JavaDoc<String JavaDoc,Object JavaDoc>();
91
92   boolean isCacheable = true;
93   protected boolean _defaultDisableEscaping;
94   Path cachePath;
95   long lastModified;
96
97   boolean _generateLocation;
98   
99   LineMap lineMap;
100
101   protected void copy(AbstractStylesheet stylesheet)
102   {
103     super.copy(stylesheet);
104
105     StylesheetImpl stylesheetImpl = (StylesheetImpl) stylesheet;
106     
107     stylesheetImpl.text = text;
108     stylesheetImpl.templates = templates;
109     stylesheetImpl._preserve = _preserve;
110     stylesheetImpl._strip = _strip;
111     stylesheetImpl._preservePrefix = _preservePrefix;
112     stylesheetImpl._stripPrefix = _stripPrefix;
113     stylesheetImpl.lineMap = lineMap;
114     stylesheetImpl._properties = _properties;
115     stylesheetImpl._defaultDisableEscaping = _defaultDisableEscaping;
116   }
117
118   public OutputFormat getOutputFormat()
119   {
120     return new OutputFormat();
121   }
122
123   public void setOutputFormat(OutputFormat output)
124   {
125   }
126
127   protected void setSpaces(HashMap JavaDoc<String JavaDoc,String JavaDoc> preserve,
128                HashMap JavaDoc<String JavaDoc,String JavaDoc> preservePrefix,
129                            HashMap JavaDoc<String JavaDoc,String JavaDoc> strip,
130                HashMap JavaDoc<String JavaDoc,String JavaDoc> stripPrefix)
131   {
132     _preserve = preserve;
133     _strip = strip;
134     _preservePrefix = preservePrefix;
135     _stripPrefix = stripPrefix;
136   }
137
138   public void setProperty(String JavaDoc name, Object JavaDoc value)
139   {
140     _properties.put(name, value);
141   }
142
143   public void setGenerateLocation(boolean generateLocation)
144   {
145     _generateLocation = generateLocation;
146   }
147
148   public boolean getGenerateLocation()
149   {
150     return _generateLocation;
151   }
152
153   public Object JavaDoc getProperty(String JavaDoc name)
154   {
155     Object JavaDoc value = _properties.get(name);
156     if (value != null)
157       return value;
158
159     return super.getProperty(name);
160   }
161
162   protected void addFunction(String JavaDoc name, XPathFun fun)
163   {
164     _funs.put(name, fun);
165   }
166
167   public void init(Path path)
168     throws Exception JavaDoc
169   {
170     super.init(path);
171
172     addFunction("system-property", new SystemPropertyFun());
173     addFunction("element-available", new ExtensionElementFun());
174     addFunction("function-available", new ExtensionFunctionFun());
175     addFunction("unparsed-entity-uri", new UnparsedEntityFun());
176   }
177
178   /**
179    * Transforms the input node to the output writer
180    *
181    * @param xml the input node to be transformed
182    * @param writer output writer receiving the output
183    * @param transformer the transformer to be used
184    */

185   public void transform(Node xml,
186                         XMLWriter writer,
187                         TransformerImpl transformer)
188     throws SAXException JavaDoc, IOException JavaDoc, TransformerException JavaDoc
189   {
190     if (xml == null)
191       throw new NullPointerException JavaDoc("can't transform null node");
192     
193     XslWriter out = new XslWriter(null, this, transformer);
194     out.init(writer);
195
196     if (_funs == null)
197       _funs = (HashMap JavaDoc) ((StylesheetImpl) _stylesheet)._funs.clone();
198     else
199       _funs.putAll((HashMap JavaDoc) ((StylesheetImpl) _stylesheet)._funs);
200
201     addFunction("document", new DocumentFun(transformer));
202     DocumentFun docFun = new DocumentFun(transformer);
203     docFun.setHtml(true);
204     addFunction("html_document", docFun);
205
206     Env env = XPath.createEnv();
207     env.setFunctions(_funs);
208     StylesheetEnv ssEnv = new StylesheetEnv();
209     ssEnv.setPath(getPath());
210     env.setStylesheetEnv(ssEnv);
211
212     out.disableEscaping(_defaultDisableEscaping);
213
214     if (_strip != null && ! _strip.isEmpty()) {
215       stripSpaces(xml);
216     }
217     
218     try {
219       _xsl_init(out, xml, env);
220
221       applyNode(out, xml, env, 0, Integer.MAX_VALUE);
222     } catch (TransformerException JavaDoc e) {
223       throw e;
224     } catch (IOException JavaDoc e) {
225       throw e;
226     } catch (SAXException JavaDoc e) {
227       throw e;
228     } catch (Exception JavaDoc e) {
229       throw new XslException(e, lineMap);
230     }
231
232     out.close();
233
234     XPath.freeEnv(env);
235
236     // funs = null;
237
}
238
239   protected void _xsl_init(XslWriter out, Node context, Env env)
240     throws Exception JavaDoc
241   {
242   }
243
244   protected Document JavaDoc ownerDocument(Node node)
245   {
246     Document JavaDoc owner = node.getOwnerDocument();
247     
248     if (owner != null)
249       return owner;
250     else
251       return (Document JavaDoc) node;
252   }
253
254   public void applyNode(XslWriter out, Node node, Env env)
255     throws Exception JavaDoc
256   {
257     applyNode(out, node, env, Integer.MIN_VALUE, Integer.MAX_VALUE);
258   }
259   
260   protected void applyNode(XslWriter out, Node node, Env env, int min, int max)
261     throws Exception JavaDoc
262   {
263     if (node == null)
264       return;
265
266     switch (node.getNodeType()) {
267     case Node.DOCUMENT_NODE:
268     case Node.DOCUMENT_FRAGMENT_NODE:
269       for (Node child = node.getFirstChild();
270            child != null;
271            child = child.getNextSibling()) {
272         applyNode(out, child, env, 0, 2147483647);
273       }
274       break;
275       
276     case Node.ELEMENT_NODE:
277       out.pushCopy(node);
278       if (node instanceof QElement) {
279         for (Node child = ((QElement) node).getFirstAttribute();
280              child != null;
281              child = child.getNextSibling()) {
282           applyNode(out, child, env, 0, 2147483647);
283         }
284       } else {
285         NamedNodeMap JavaDoc attributeMap = ((Element) node).getAttributes();
286         int size = attributeMap.getLength();
287         for (int i = 0; i < size; i++) {
288           Node child = attributeMap.item(i);
289           
290           applyNode(out, child, env, 0, 2147483647);
291         }
292       }
293       
294       for (Node child = node.getFirstChild();
295            child != null;
296            child = child.getNextSibling()) {
297         applyNode(out, child, env, 0, 2147483647);
298       }
299       out.popCopy(node);
300       break;
301
302     case Node.TEXT_NODE:
303     case Node.CDATA_SECTION_NODE:
304       String JavaDoc value = node.getNodeValue();
305       out.print(value);
306       return;
307       
308     case Node.ATTRIBUTE_NODE:
309       out.pushCopy(node);
310       out.popCopy(node);
311       break;
312       
313     case Node.ENTITY_REFERENCE_NODE:
314       out.pushCopy(node);
315       out.popCopy(node);
316       break;
317     }
318   }
319   
320   /**
321    * Gets a template.
322    *
323    * Only those templates with importance between min and max are considered.
324    * For apply-templates, min = 0, and max = Infinity,
325    *
326    * @param min minimum allowed importance
327    * @param max maximum allowed importance
328    */

329   protected Template getTemplate(HashMap JavaDoc templates,
330                                  Node node, Env env, int min, int max)
331     throws XPathException
332   {
333     Template template = null;
334
335     Template []templateList = (Template []) templates.get(node.getNodeName());
336     if (templateList == null)
337       templateList = (Template []) templates.get("*");
338     
339     for (int i = 0; templateList != null && i < templateList.length; i++) {
340       Template subtemplate = templateList[i];
341
342       if (min <= subtemplate.maxImportance &&
343       subtemplate.maxImportance <= max &&
344       subtemplate.pattern.match(node, env)) {
345         return subtemplate;
346       }
347     }
348
349     return null;
350   }
351
352   /**
353    * The default rule when no templates match. By default, it
354    * calls apply-template on element children and copies text. All
355    * other nodes are stripped.
356    *
357    * @param out the current writer.
358    * @param node the current node.
359    * @param env the xpath environment.
360    */

361   protected void applyNodeDefault(XslWriter out, Node node, Env env)
362     throws Exception JavaDoc
363   {
364     switch (node.getNodeType()) {
365     case Node.TEXT_NODE:
366     case Node.CDATA_SECTION_NODE:
367       if (_generateLocation && node instanceof QAbstractNode)
368         out.setLocation(((QAbstractNode) node).getBaseURI(),
369             ((QAbstractNode) node).getFilename(),
370                         ((QAbstractNode) node).getLine());
371       String JavaDoc value = node.getNodeValue();
372       out.print(value);
373       return;
374       
375     case Node.ATTRIBUTE_NODE:
376     case Node.ENTITY_REFERENCE_NODE:
377       out.print(node.getNodeValue());
378       break;
379
380     case Node.ELEMENT_NODE:
381     case Node.DOCUMENT_NODE:
382       throw new RuntimeException JavaDoc();
383     }
384   }
385
386   public void printValue(XslWriter out, Node node) throws IOException JavaDoc
387   {
388     if (node != null)
389       out.print(getNodeValue(node));
390   }
391
392   public String JavaDoc getNodeValue(Node node)
393   {
394     CharBuffer cb = new CharBuffer();
395
396     nodeValue(cb, node);
397
398     return cb.toString();
399   }
400
401   private void nodeValue(CharBuffer cb, Node node)
402   {
403     if (node == null)
404       return;
405
406     switch (node.getNodeType()) {
407     case Node.ELEMENT_NODE:
408       for (Node child = node.getFirstChild();
409        child != null;
410        child = child.getNextSibling()) {
411     switch (child.getNodeType()) {
412     case Node.ELEMENT_NODE:
413     case Node.TEXT_NODE:
414     case Node.CDATA_SECTION_NODE:
415     case Node.ENTITY_REFERENCE_NODE:
416       nodeValue(cb, child);
417       break;
418     }
419       }
420       break;
421
422     case Node.ENTITY_REFERENCE_NODE:
423       cb.append('&');
424       cb.append(node.getNodeName());
425       cb.append(';');
426       break;
427
428     case Node.DOCUMENT_NODE:
429       Document JavaDoc doc = (Document JavaDoc) node;
430       nodeValue(cb, doc.getDocumentElement());
431       break;
432
433     case Node.TEXT_NODE:
434     case Node.CDATA_SECTION_NODE:
435       String JavaDoc value = node.getNodeValue();
436       cb.append(value);
437       break;
438
439     default:
440       cb.append(node.getNodeValue());
441       break;
442     }
443   }
444
445   protected ArrayList JavaDoc xslSort(Node node, Env env, AbstractPattern pattern,
446                   Sort []sortList)
447     throws Exception JavaDoc
448   {
449     ArrayList JavaDoc<Node> sortKeys = new ArrayList JavaDoc<Node>();
450
451     Iterator<Node> sortIter;
452     NodeIterator iter = pattern.select(node, env);
453
454     while (iter.hasNext()) {
455       Node child = iter.next();
456       sortKeys.add(child);
457     }
458
459     int []map = new int[sortKeys.size()];
460     for (int i = map.length - 1; i >= 0; i--)
461       map[i] = i;
462
463     int []workMap = new int[map.length];
464     
465     Object JavaDoc []values = new Object JavaDoc[map.length * sortList.length];
466     
467     int size = map.length;
468     for (int i = 0; i < size; i++) {
469       Node child = (Node) sortKeys.get(i);
470       
471       env.setPosition(i + 1);
472       // XXX: set last() as well
473

474       for (int j = 0; j < sortList.length; j++) {
475         Sort sort = sortList[j];
476         Object JavaDoc value = sort.sortValue(child, env);
477
478         values[i * sortList.length + j] = value;
479       }
480     }
481     
482     boolean []ascendingList = new boolean[sortList.length];
483
484     for (int i = 0; i < ascendingList.length; i++) {
485       Expr isAscending = sortList[i].getAscending();
486       if (isAscending == null || isAscending.evalBoolean(node, env))
487         ascendingList[i] = true;
488     }
489
490     Comparator JavaDoc []comparatorList = new Comparator JavaDoc[sortList.length];
491
492     for (int i = 0; i < comparatorList.length; i++) {
493       Expr langExpr = sortList[i].getLang();
494       String JavaDoc lang = null;
495
496       if (langExpr != null) {
497     lang = langExpr.evalString(node, env);
498       }
499
500       if (lang != null)
501     comparatorList[i] = getComparator(lang);
502     }
503
504     int []caseOrderList = new int[sortList.length];
505
506     for (int i = 0; i < caseOrderList.length; i++) {
507       Expr caseOrder = sortList[i].getCaseOrder();
508       if (caseOrder == null)
509     caseOrderList[i] = Sort.NO_CASE_ORDER;
510       else if (caseOrder.evalBoolean(node, env))
511         caseOrderList[i] = Sort.UPPER_FIRST;
512       else
513         caseOrderList[i] = Sort.LOWER_FIRST;
514     }
515
516     sort(values, sortList, comparatorList, ascendingList, caseOrderList,
517      0, map.length, map, workMap);
518
519     ArrayList JavaDoc sortedKeys = new ArrayList JavaDoc();
520
521     for (int i = 0; i < map.length; i++)
522       sortedKeys.add(sortKeys.get(map[i]));
523
524     return sortedKeys;
525   }
526
527   /**
528    * Returns the comparator for the language.
529    */

530   private Comparator JavaDoc getComparator(String JavaDoc lang)
531   {
532     Locale JavaDoc locale = getLocale(lang);
533
534     return java.text.Collator.getInstance(locale);
535   }
536
537   /**
538    * Returns the locale for the language.
539    */

540   private Locale JavaDoc getLocale(String JavaDoc lang)
541   {
542     int p = lang.indexOf('-');
543     Locale JavaDoc locale = null;
544
545     if (p < 0) {
546       locale = new Locale JavaDoc(lang, "");
547     }
548     else {
549       String JavaDoc language = lang.substring(0, p);
550           
551       int q = lang.indexOf(p + 1, '-');
552
553       if (q < 0) {
554     String JavaDoc country = lang.substring(p + 1);
555
556     locale = new Locale JavaDoc(language, country);
557       }
558       else {
559     String JavaDoc country = lang.substring(p + 1, q);
560     String JavaDoc variant = lang.substring(q);
561
562     locale = new Locale JavaDoc(language, country, variant);
563       }
564     }
565
566     return locale;
567   }
568
569   /**
570    * Sorts a subsequence.
571    *
572    * @param head the start of the subsequence
573    * @param tail the tail of the subsequence
574    */

575   private void sort(Object JavaDoc []values, Sort []sortList,
576             Comparator JavaDoc []comparatorList,
577             boolean []ascendingList,
578             int []caseOrder,
579                     int head, int tail,
580                     int map[], int []workMap)
581   {
582     int length = tail - head;
583     if (length <= 1)
584       return;
585
586     // shortcut when only have two items
587
if (length == 2) {
588       int a = map[head];
589       int b = map[head + 1];
590
591       if (lessThan(values, sortList, comparatorList,
592            ascendingList, caseOrder, b, a)) {
593         map[head] = b;
594         map[head + 1] = a;
595       }
596       return;
597     }
598     // shortcut when only have three items
599
else if (length == 3) {
600       int a = map[head];
601       int b = map[head + 1];
602       int c = map[head + 2];
603       
604       if (lessThan(values, sortList, comparatorList,
605            ascendingList, caseOrder, b, a)) {
606         map[head] = b;
607         map[head + 1] = a;
608         a = map[head];
609         b = map[head + 1];
610       }
611
612       if (! lessThan(values, sortList, comparatorList,
613              ascendingList, caseOrder, c, b)) {
614       }
615       else if (lessThan(values, sortList, comparatorList,
616             ascendingList, caseOrder, c, a)) {
617         map[head] = c;
618         map[head + 1] = a;
619         map[head + 2] = b;
620       }
621       else {
622         map[head + 1] = c;
623         map[head + 2] = b;
624       }
625
626       return;
627     }
628
629     int pivotIndex = (head + tail) / 2;
630     int pivot = map[pivotIndex];
631     int top = tail;
632
633     // values greater than the pivot value are put in the work map
634
for (int i = tail - 1; i >= head; i--) {
635       if (lessThan(values, sortList, comparatorList,
636            ascendingList, caseOrder, pivot, map[i])) {
637         workMap[--top] = map[i];
638         map[i] = -1;
639       }
640     }
641
642     // if the pivot is the max, need to shift equals
643
if (top == tail) {
644       // values greater than the pivot value are put in the work map
645
for (int i = tail - 1; i >= head; i--) {
646         if (! lessThan(values, sortList, comparatorList,
647                ascendingList, caseOrder, map[i], pivot)) {
648           workMap[--top] = map[i];
649           map[i] = -1;
650         }
651       }
652
653       // If all entries are equal to the pivot, we're done
654
if (top == head) {
655         for (int i = head; i < tail; i++)
656           map[i] = workMap[i];
657         return;
658       }
659     }
660     
661     // shift down the values less than the pivot
662
int center = head;
663     for (int i = head; i < tail; i++) {
664       if (map[i] >= 0)
665         map[center++] = map[i];
666     }
667
668     for (int i = center; i < tail; i++)
669       map[i] = workMap[i];
670
671     sort(values, sortList, comparatorList, ascendingList, caseOrder,
672      head, center, map, workMap);
673     sort(values, sortList, comparatorList, ascendingList, caseOrder,
674      center, tail, map, workMap);
675   }
676
677   /**
678    * Swaps two items in the map.
679    */

680   private void swap(int []map, int a, int b)
681   {
682     int ka = map[a];
683     int kb = map[b];
684     
685     map[b] = ka;
686     map[a] = kb;
687   }
688
689   /**
690    * Returns true if the first value is strictly less than the second.
691    */

692   private boolean lessThan(Object JavaDoc []values,
693                            Sort []sortList,
694                Comparator JavaDoc []comparatorList,
695                boolean []ascendingList,
696                int []caseOrder,
697                            int ai, int bi)
698   {
699     int len = sortList.length;
700
701     for (int i = 0; i < len; i++) {
702       Object JavaDoc a = values[len * ai + i];
703       Object JavaDoc b = values[len * bi + i];
704
705       int cmp = sortList[i].cmp(a, b, comparatorList[i],
706                 ascendingList[i], caseOrder[i]);
707       if (cmp < 0)
708     return true;
709       else if (cmp > 0)
710     return false;
711     }
712
713     return false;
714   }
715
716   public void singleNumber(XslWriter out, Node node, Env env,
717                AbstractPattern countPattern,
718                AbstractPattern fromPattern,
719                XslNumberFormat format)
720     throws Exception JavaDoc
721   {
722     if (countPattern == null)
723       countPattern = XPath.parseMatch(node.getNodeName()).getPattern();
724
725     IntArray numbers = new IntArray();
726     for (; node != null; node = node.getParentNode()) {
727       if (countPattern.match(node, env)) {
728     numbers.add(countPreviousSiblings(node, env, countPattern));
729     break;
730       }
731       if (fromPattern != null && fromPattern.match(node, env))
732     break;
733     }
734     if (fromPattern != null && ! findFromAncestor(node, env, fromPattern))
735       numbers.clear();
736
737     format.format(out, numbers);
738   }
739
740   public void multiNumber(XslWriter out, Node node, Env env,
741               AbstractPattern countPattern,
742               AbstractPattern fromPattern,
743               XslNumberFormat format)
744     throws Exception JavaDoc
745   {
746     if (countPattern == null)
747       countPattern = XPath.parseMatch(node.getNodeName()).getPattern();
748
749     IntArray numbers = new IntArray();
750     for (; node != null; node = node.getParentNode()) {
751       if (countPattern.match(node, env))
752     numbers.add(countPreviousSiblings(node, env, countPattern));
753
754       if (fromPattern != null && fromPattern.match(node, env))
755     break;
756     }
757     if (fromPattern != null && ! findFromAncestor(node, env, fromPattern))
758       numbers.clear();
759
760     format.format(out, numbers);
761   }
762
763   public void anyNumber(XslWriter out, Node node, Env env,
764             AbstractPattern countPattern,
765             AbstractPattern fromPattern,
766             XslNumberFormat format)
767     throws Exception JavaDoc
768   {
769     if (countPattern == null)
770       countPattern = XPath.parseMatch(node.getNodeName()).getPattern();
771
772     IntArray numbers = new IntArray();
773     int count = 0;
774     for (; node != null; node = XmlUtil.getPrevious(node)) {
775       if (countPattern.match(node, env))
776     count++;
777
778       if (fromPattern != null && fromPattern.match(node, env))
779     break;
780     }
781     numbers.add(count);
782     if (fromPattern != null && ! findFromAncestor(node, env, fromPattern))
783       numbers.clear();
784
785     format.format(out, numbers);
786   }
787
788   public void exprNumber(XslWriter out, Node node, Env env, Expr expr,
789              XslNumberFormat format)
790     throws Exception JavaDoc
791   {
792     IntArray numbers = new IntArray();
793     numbers.add((int) expr.evalNumber(node, env));
794
795     format.format(out, numbers);
796   }
797
798   private int countPreviousSiblings(Node node, Env env, String JavaDoc name)
799   {
800     int count = 1;
801     for (node = node.getPreviousSibling();
802      node != null;
803      node = node.getPreviousSibling()) {
804       if (node.getNodeType() == node.ELEMENT_NODE &&
805       node.getNodeName().equals(name))
806     count++;
807     }
808
809     return count;
810   }
811
812   private int countPreviousSiblings(Node node, Env env, AbstractPattern pattern)
813     throws XPathException
814   {
815     int count = 1;
816     for (node = node.getPreviousSibling();
817      node != null;
818      node = node.getPreviousSibling()) {
819       if (pattern.match(node, env))
820     count++;
821     }
822
823     return count;
824   }
825
826   private boolean findFromAncestor(Node node, Env env, AbstractPattern pattern)
827     throws XPathException
828   {
829     for (; node != null; node = node.getParentNode())
830       if (pattern.match(node, env))
831     return true;
832
833     return false;
834   }
835
836   /**
837    * Strips the spaces from a tree.
838    */

839   void stripSpaces(Node node)
840   {
841     Node child = node.getFirstChild();
842
843     while (child != null) {
844       Node next = child.getNextSibling();
845       
846       if (child instanceof Element) {
847     stripSpaces(child);
848       }
849       else if (child instanceof Text JavaDoc) {
850     String JavaDoc data = ((Text JavaDoc) child).getData();
851
852     boolean hasContent = false;
853     for (int i = data.length() - 1; i >= 0; i--) {
854       char ch = data.charAt(i);
855
856       if (! XmlChar.isWhitespace(ch)) {
857         hasContent = true;
858         break;
859       }
860     }
861
862     if (! hasContent && isStripSpaces(node)) {
863       node.removeChild(child);
864     }
865       }
866
867       child = next;
868     }
869   }
870   /**
871    * Returns true if the node is a pure whitespace text node.
872    */

873   boolean isStripSpaces(Node node)
874   {
875     if (_strip == null)
876       return false;
877     
878     for (Node ptr = node; ptr != null; ptr = ptr.getParentNode()) {
879       if (ptr instanceof Element) {
880     Element elt = (Element) ptr;
881     String JavaDoc space = elt.getAttribute("xml:space");
882     if (space != null && space.equals("preserve"))
883       return false;
884     else if (space != null)
885       break;
886       }
887     }
888     String JavaDoc name = node.getNodeName();
889     if (_preserve.get(node.getNodeName()) != null)
890       return false;
891     else if (_strip.get(node.getNodeName()) != null)
892       return true;
893
894     CauchoNode cnode = (CauchoNode) node;
895     String JavaDoc nsStar = cnode.getPrefix();
896     if (_preservePrefix.get(nsStar) != null)
897       return false;
898     else if (_stripPrefix.get(nsStar) != null)
899       return true;
900
901     return _strip.get("*") != null;
902   }
903
904   /**
905    * Merges two template arrays into the final one.
906    */

907   protected static Template []mergeTemplates(Template []star,
908                                              Template []templates)
909   {
910     Template []merged = new Template[star.length + templates.length];
911
912     int i = 0;
913     int j = 0;
914     int k = 0;
915
916     while (i < star.length && j < templates.length) {
917       if (star[i].compareTo(templates[j]) > 0)
918         merged[k++] = star[i++];
919       else
920         merged[k++] = templates[j++];
921     }
922
923     for (; i < star.length; i++)
924       merged[k++] = star[i];
925
926     for (; j < templates.length; j++)
927       merged[k++] = templates[j];
928
929     return merged;
930   }
931 }
932
Popular Tags