OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libjava/] [classpath/] [gnu/] [xml/] [transform/] [Stylesheet.java] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* Stylesheet.java --
2
   Copyright (C) 2004 Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
package gnu.xml.transform;
39
 
40
import java.text.DecimalFormat;
41
import java.text.DecimalFormatSymbols;
42
import java.util.ArrayList;
43
import java.util.Collection;
44
import java.util.Collections;
45
import java.util.HashSet;
46
import java.util.Iterator;
47
import java.util.LinkedHashMap;
48
import java.util.LinkedHashSet;
49
import java.util.LinkedList;
50
import java.util.List;
51
import java.util.Map;
52
import java.util.Set;
53
import java.util.StringTokenizer;
54
import java.util.TreeSet;
55
import javax.xml.XMLConstants;
56
import javax.xml.namespace.NamespaceContext;
57
import javax.xml.namespace.QName;
58
import javax.xml.transform.Source;
59
import javax.xml.transform.TransformerConfigurationException;
60
import javax.xml.transform.TransformerException;
61
import javax.xml.xpath.XPathFunction;
62
import javax.xml.xpath.XPathFunctionResolver;
63
import javax.xml.xpath.XPathExpressionException;
64
import org.w3c.dom.Attr;
65
import org.w3c.dom.Document;
66
import org.w3c.dom.DOMException;
67
import org.w3c.dom.Element;
68
import org.w3c.dom.NamedNodeMap;
69
import org.w3c.dom.Node;
70
import org.w3c.dom.Text;
71
import org.w3c.dom.UserDataHandler;
72
import gnu.xml.xpath.Expr;
73
import gnu.xml.xpath.NameTest;
74
import gnu.xml.xpath.NodeTypeTest;
75
import gnu.xml.xpath.Pattern;
76
import gnu.xml.xpath.Selector;
77
import gnu.xml.xpath.Root;
78
import gnu.xml.xpath.Test;
79
import gnu.xml.xpath.XPathImpl;
80
 
81
/**
82
 * An XSL stylesheet.
83
 *
84
 * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
85
 */
86
class Stylesheet
87
  implements NamespaceContext, XPathFunctionResolver, UserDataHandler, Cloneable
88
{
89
 
90
  static final String XSL_NS = "http://www.w3.org/1999/XSL/Transform";
91
 
92
  static final int OUTPUT_XML = 0;
93
  static final int OUTPUT_HTML = 1;
94
  static final int OUTPUT_TEXT = 2;
95
 
96
  final TransformerFactoryImpl factory;
97
  TransformerImpl transformer;
98
  Stylesheet parent;
99
  final XPathImpl xpath;
100
  final String systemId;
101
  final int precedence;
102
 
103
  final boolean debug;
104
 
105
  /**
106
   * Version of XSLT.
107
   */
108
  String version;
109
 
110
  Collection extensionElementPrefixes;
111
  Collection excludeResultPrefixes;
112
 
113
  /**
114
   * Set of element names for which we should strip whitespace.
115
   */
116
  Set stripSpace;
117
 
118
  /**
119
   * Set of element names for which we should preserve whitespace.
120
   */
121
  Set preserveSpace;
122
 
123
  /**
124
   * Output options.
125
   */
126
  Node output;
127
  int outputMethod;
128
  String outputVersion;
129
  String outputEncoding;
130
  boolean outputOmitXmlDeclaration;
131
  boolean outputStandalone;
132
  String outputPublicId;
133
  String outputSystemId;
134
  Collection outputCdataSectionElements;
135
  boolean outputIndent;
136
  String outputMediaType;
137
 
138
  /**
139
   * Keys.
140
   */
141
  Collection keys;
142
 
143
  /**
144
   * Decimal formats.
145
   */
146
  Map decimalFormats;
147
 
148
  /**
149
   * Namespace aliases.
150
   */
151
  Map namespaceAliases;
152
 
153
  /**
154
   * Attribute-sets.
155
   */
156
  List attributeSets;
157
 
158
  /**
159
   * Variables.
160
   */
161
  List variables;
162
 
163
  /**
164
   * Variable and parameter bindings.
165
   */
166
  Bindings bindings;
167
 
168
  /**
169
   * Templates.
170
   */
171
  LinkedList templates;
172
 
173
  TemplateNode builtInNodeTemplate;
174
  TemplateNode builtInTextTemplate;
175
 
176
  /**
177
   * Holds the current node while parsing.
178
   * Necessary to associate the document function with its declaring node,
179
   * to resolve namespaces, and to maintain the current node for the
180
   * current() function.
181
   */
182
  Node current;
183
 
184
  /**
185
   * Set by a terminating message.
186
   */
187
  transient boolean terminated;
188
 
189
  /**
190
   * Current template in force.
191
   */
192
  transient Template currentTemplate;
193
 
194
  Stylesheet(TransformerFactoryImpl factory,
195
             Stylesheet parent,
196
             Document doc,
197
             String systemId,
198
             int precedence)
199
    throws TransformerConfigurationException
200
  {
201
    this.factory = factory;
202
    this.systemId = systemId;
203
    this.precedence = precedence;
204
    this.parent = parent;
205
    extensionElementPrefixes = new HashSet();
206
    excludeResultPrefixes = new HashSet();
207
    stripSpace = new LinkedHashSet();
208
    preserveSpace = new LinkedHashSet();
209
    outputCdataSectionElements = new LinkedHashSet();
210
    xpath = (XPathImpl) factory.xpathFactory.newXPath();
211
    if (parent == null)
212
      {
213
        bindings = new Bindings(this);
214
        attributeSets = new LinkedList();
215
        variables = new LinkedList();
216
        namespaceAliases = new LinkedHashMap();
217
        templates = new LinkedList();
218
        keys = new LinkedList();
219
        decimalFormats = new LinkedHashMap();
220
        initDefaultDecimalFormat();
221
        xpath.setNamespaceContext(this);
222
        xpath.setXPathFunctionResolver(this);
223
      }
224
    else
225
      {
226
        /* Test for import circularity */
227
        for (Stylesheet ctx = this; ctx.parent != null; ctx = ctx.parent)
228
          {
229
            if (systemId != null && systemId.equals(ctx.parent.systemId))
230
              {
231
                String msg = "circularity importing " + systemId;
232
                throw new TransformerConfigurationException(msg);
233
              }
234
          }
235
        /* OK */
236
        Stylesheet root = getRootStylesheet();
237
        bindings = root.bindings;
238
        attributeSets = root.attributeSets;
239
        variables = root.variables;
240
        namespaceAliases = root.namespaceAliases;
241
        templates = root.templates;
242
        keys = root.keys;
243
        decimalFormats = root.decimalFormats;
244
        xpath.setNamespaceContext(root);
245
        xpath.setXPathFunctionResolver(root);
246
      }
247
    xpath.setXPathVariableResolver(bindings);
248
 
249
    Test anyNode = new NodeTypeTest((short) 0);
250
    List tests = Collections.singletonList(anyNode);
251
    builtInNodeTemplate =
252
      new ApplyTemplatesNode(new Selector(Selector.CHILD, tests),
253
                             null, null, null, true);
254
    builtInTextTemplate =
255
      new ValueOfNode(new Selector(Selector.SELF, tests),
256
                      false);
257
 
258
    parse(doc.getDocumentElement(), true);
259
    current = doc; // Alow namespace resolution during processing
260
 
261
    debug = ("yes".equals(System.getProperty("xsl.debug")));
262
 
263
    if (debug)
264
      {
265
        System.err.println("Stylesheet: " + doc.getDocumentURI());
266
        for (Iterator i = templates.iterator(); i.hasNext(); )
267
          {
268
            Template t = (Template) i.next();
269
            t.list(System.err);
270
            System.err.println("--------------------");
271
          }
272
      }
273
  }
274
 
275
  Stylesheet getRootStylesheet()
276
  {
277
    Stylesheet stylesheet = this;
278
    while (stylesheet.parent != null)
279
      {
280
        stylesheet = stylesheet.parent;
281
      }
282
    return stylesheet;
283
  }
284
 
285
  void initDefaultDecimalFormat()
286
  {
287
    DecimalFormat defaultDecimalFormat = new DecimalFormat();
288
    DecimalFormatSymbols symbols = new DecimalFormatSymbols();
289
    symbols.setDecimalSeparator('.');
290
    symbols.setGroupingSeparator(',');
291
    symbols.setPercent('%');
292
    symbols.setPerMill('\u2030');
293
    symbols.setZeroDigit('0');
294
    symbols.setDigit('#');
295
    symbols.setPatternSeparator(';');
296
    symbols.setInfinity("Infinity");
297
    symbols.setNaN("NaN");
298
    symbols.setMinusSign('-');
299
    defaultDecimalFormat.setDecimalFormatSymbols(symbols);
300
    decimalFormats.put(null, defaultDecimalFormat);
301
  }
302
 
303
  // -- Cloneable --
304
 
305
  public Object clone()
306
  {
307
    try
308
      {
309
        Stylesheet clone = (Stylesheet) super.clone();
310
        clone.bindings = (Bindings) bindings.clone();
311
 
312
        LinkedList templates2 = new LinkedList();
313
        for (Iterator i = templates.iterator(); i.hasNext(); )
314
          {
315
            Template t = (Template) i.next();
316
            templates2.add(t.clone(clone));
317
          }
318
        clone.templates = templates2;
319
 
320
        LinkedList attributeSets2 = new LinkedList();
321
        for (Iterator i = attributeSets.iterator(); i.hasNext(); )
322
          {
323
            AttributeSet as = (AttributeSet) i.next();
324
            attributeSets2.add(as.clone(clone));
325
          }
326
        clone.attributeSets = attributeSets2;
327
 
328
        LinkedList variables2 = new LinkedList();
329
        for (Iterator i = variables.iterator(); i.hasNext(); )
330
          {
331
            ParameterNode var = (ParameterNode) i.next();
332
            variables2.add(var.clone(clone));
333
          }
334
        clone.variables = variables2;
335
 
336
        LinkedList keys2 = new LinkedList();
337
        for (Iterator i = keys.iterator(); i.hasNext(); )
338
          {
339
            Key k = (Key) i.next();
340
            keys2.add(k.clone(clone));
341
          }
342
        clone.keys = keys2;
343
 
344
        return clone;
345
      }
346
    catch (CloneNotSupportedException e)
347
      {
348
        throw new Error(e.getMessage());
349
      }
350
  }
351
 
352
  // -- Variable evaluation --
353
 
354
  void initTopLevelVariables(Node context)
355
    throws TransformerException
356
  {
357
    current = context;
358
    // Sort the variables into order
359
    // See XSLT 11.4: "If the template or expression specifying the value of
360
    // a global variable x references a global variable y, then the value
361
    // for y must be computed before the value of x."
362
    List topLevel = new ArrayList(variables);
363
    Collections.sort(topLevel);
364
    for (Iterator i = topLevel.iterator(); i.hasNext(); )
365
      {
366
        ParameterNode var = (ParameterNode) i.next();
367
        bindings.set(var.name,
368
                     var.getValue(this, null, context, 1, 1),
369
                     var.type);
370
      }
371
    current = null;
372
  }
373
 
374
  // -- NamespaceContext --
375
 
376
  public String getNamespaceURI(String prefix)
377
  {
378
    return (current == null) ? null : current.lookupNamespaceURI(prefix);
379
  }
380
 
381
  public String getPrefix(String namespaceURI)
382
  {
383
    return (current == null) ? null : current.lookupPrefix(namespaceURI);
384
  }
385
 
386
  public Iterator getPrefixes(String namespaceURI)
387
  {
388
    // TODO
389
    return Collections.singleton(getPrefix(namespaceURI)).iterator();
390
  }
391
 
392
  final QName getQName(String name)
393
  {
394
    String localName = name, uri = null, prefix = null;
395
    int ci = name.indexOf(':');
396
    if (ci != -1)
397
      {
398
        prefix = name.substring(0, ci);
399
        localName = name.substring(ci + 1);
400
        uri = getNamespaceURI(prefix);
401
      }
402
    return new QName(uri, localName, prefix);
403
  }
404
 
405
  // -- Template selection --
406
 
407
  TemplateNode getTemplate(QName mode, Node context, boolean applyImports)
408
    throws TransformerException
409
  {
410
    if (debug)
411
      {
412
        System.err.println("getTemplate: mode="+mode+" context="+context);
413
      }
414
    Set candidates = new TreeSet();
415
    for (Iterator j = templates.iterator(); j.hasNext(); )
416
      {
417
        Template t = (Template) j.next();
418
        boolean isMatch = t.matches(mode, context);
419
        if (applyImports)
420
          {
421
            if (currentTemplate == null)
422
              {
423
                String msg = "current template may not be null " +
424
                  "during apply-imports";
425
                throw new TransformerException(msg);
426
              }
427
            if (!currentTemplate.imports(t))
428
              {
429
                isMatch = false;
430
              }
431
          }
432
        //System.err.println("\t"+context+" "+t+"="+isMatch);
433
        if (isMatch)
434
          {
435
            candidates.add(t);
436
          }
437
      }
438
    //System.err.println("\tcandidates="+candidates);
439
    if (candidates.isEmpty())
440
      {
441
        // Apply built-in template
442
        // Current template is unchanged
443
        if (debug)
444
          {
445
            System.err.println("\tbuiltInTemplate context="+context);
446
          }
447
        switch (context.getNodeType())
448
          {
449
          case Node.ELEMENT_NODE:
450
          case Node.DOCUMENT_NODE:
451
          case Node.DOCUMENT_FRAGMENT_NODE:
452
          case Node.PROCESSING_INSTRUCTION_NODE:
453
          case Node.COMMENT_NODE:
454
            return builtInNodeTemplate;
455
          case Node.TEXT_NODE:
456
          case Node.ATTRIBUTE_NODE:
457
            return builtInTextTemplate;
458
          default:
459
            return null;
460
          }
461
      }
462
    else
463
      {
464
        Template t = (Template) candidates.iterator().next();
465
        // Set current template
466
        currentTemplate = t;
467
        if (debug)
468
          {
469
            System.err.println("\ttemplate="+t+" context="+context);
470
          }
471
        return t.node;
472
      }
473
  }
474
 
475
  TemplateNode getTemplate(QName mode, QName name)
476
    throws TransformerException
477
  {
478
    //System.err.println("getTemplate: mode="+mode+" name="+name);
479
    Set candidates = new TreeSet();
480
    for (Iterator j = templates.iterator(); j.hasNext(); )
481
      {
482
        Template t = (Template) j.next();
483
        boolean isMatch = t.matches(name);
484
        //System.err.println("\t"+name+" "+t+"="+isMatch);
485
        if (isMatch)
486
          {
487
            candidates.add(t);
488
          }
489
      }
490
    if (candidates.isEmpty())
491
      {
492
        return null;
493
        //throw new TransformerException("template '" + name + "' not found");
494
      }
495
    Template t = (Template) candidates.iterator().next();
496
    //System.err.println("\ttemplate="+t+" context="+context);
497
    return t.node;
498
  }
499
 
500
  /**
501
   * template
502
   */
503
  final Template parseTemplate(Node node, NamedNodeMap attrs)
504
    throws TransformerConfigurationException, XPathExpressionException
505
  {
506
    String n = getAttribute(attrs, "name");
507
    QName name = (n == null) ? null : getQName(n);
508
    String m = getAttribute(attrs, "match");
509
    Pattern match = null;
510
    if (m != null)
511
      {
512
        try
513
          {
514
            match = (Pattern) xpath.compile(m);
515
          }
516
        catch (ClassCastException e)
517
          {
518
            String msg = "illegal pattern: " + m;
519
            throw new TransformerConfigurationException(msg);
520
          }
521
      }
522
    String p = getAttribute(attrs, "priority");
523
    String mm = getAttribute(attrs, "mode");
524
    QName mode = (mm == null) ? null : getQName(mm);
525
    double priority = (p == null) ? Template.DEFAULT_PRIORITY :
526
      Double.parseDouble(p);
527
    Node children = node.getFirstChild();
528
    return new Template(this, name, match, parse(children),
529
                        precedence, priority, mode);
530
  }
531
 
532
  /**
533
   * output
534
   */
535
  final void parseOutput(Node node, NamedNodeMap attrs)
536
    throws TransformerConfigurationException
537
  {
538
    output = node;
539
    String method = getAttribute(attrs, "method");
540
    if ("xml".equals(method) || method == null)
541
      {
542
        outputMethod = OUTPUT_XML;
543
      }
544
    else if ("html".equals(method))
545
      {
546
        outputMethod = OUTPUT_HTML;
547
      }
548
    else if ("text".equals(method))
549
      {
550
        outputMethod = OUTPUT_TEXT;
551
      }
552
    else
553
      {
554
        String msg = "unsupported output method: " + method;
555
        DOMSourceLocator l = new DOMSourceLocator(node);
556
        throw new TransformerConfigurationException(msg, l);
557
      }
558
    outputPublicId = getAttribute(attrs, "public-id");
559
    outputSystemId = getAttribute(attrs, "system-id");
560
    outputEncoding = getAttribute(attrs, "encoding");
561
    String indent = getAttribute(attrs, "indent");
562
    if (indent != null)
563
      {
564
        outputIndent = "yes".equals(indent);
565
      }
566
    outputVersion = getAttribute(attrs, "version");
567
    String omitXmlDecl = getAttribute(attrs, "omit-xml-declaration");
568
    if (omitXmlDecl != null)
569
      {
570
        outputOmitXmlDeclaration = "yes".equals(omitXmlDecl);
571
      }
572
    String standalone = getAttribute(attrs, "standalone");
573
    if (standalone != null)
574
      {
575
        outputStandalone = "yes".equals(standalone);
576
      }
577
    outputMediaType = getAttribute(attrs, "media-type");
578
    String cdataSectionElements =
579
      getAttribute(attrs, "cdata-section-elements");
580
    if (cdataSectionElements != null)
581
      {
582
        StringTokenizer st = new StringTokenizer(cdataSectionElements, " ");
583
        while (st.hasMoreTokens())
584
          {
585
            outputCdataSectionElements.add(st.nextToken());
586
          }
587
      }
588
  }
589
 
590
  /**
591
   * key
592
   */
593
  final void parseKey(Node node, NamedNodeMap attrs)
594
    throws TransformerConfigurationException, XPathExpressionException
595
  {
596
    String n = getRequiredAttribute(attrs, "name", node);
597
    String m = getRequiredAttribute(attrs, "match", node);
598
    String u = getRequiredAttribute(attrs, "use", node);
599
    QName name = getQName(n);
600
    Expr use = (Expr) xpath.compile(u);
601
    try
602
      {
603
        Pattern match = (Pattern) xpath.compile(m);
604
        Key key = new Key(name, match, use);
605
        keys.add(key);
606
      }
607
    catch (ClassCastException e)
608
      {
609
        throw new TransformerConfigurationException("invalid pattern: " + m);
610
      }
611
  }
612
 
613
  /**
614
   * decimal-format
615
   */
616
  final void parseDecimalFormat(Node node, NamedNodeMap attrs)
617
    throws TransformerConfigurationException
618
  {
619
    String dfName = getAttribute(attrs, "name");
620
    DecimalFormat df = new DecimalFormat();
621
    DecimalFormatSymbols symbols = new DecimalFormatSymbols();
622
    symbols.setDecimalSeparator(parseDFChar(attrs, "decimal-separator", '.'));
623
    symbols.setGroupingSeparator(parseDFChar(attrs, "grouping-separator", ','));
624
    symbols.setInfinity(parseDFString(attrs, "infinity", "Infinity"));
625
    symbols.setMinusSign(parseDFChar(attrs, "minus-sign", '-'));
626
    symbols.setNaN(parseDFString(attrs, "NaN", "NaN"));
627
    symbols.setPercent(parseDFChar(attrs, "percent", '%'));
628
    symbols.setPerMill(parseDFChar(attrs, "per-mille", '\u2030'));
629
    symbols.setZeroDigit(parseDFChar(attrs, "zero-digit", '0'));
630
    symbols.setDigit(parseDFChar(attrs, "digit", '#'));
631
    symbols.setPatternSeparator(parseDFChar(attrs, "pattern-separator", ';'));
632
    df.setDecimalFormatSymbols(symbols);
633
    decimalFormats.put(dfName, df);
634
  }
635
 
636
  private final char parseDFChar(NamedNodeMap attrs, String name, char def)
637
    throws TransformerConfigurationException
638
  {
639
    Node attr = attrs.getNamedItem(name);
640
    try
641
      {
642
        return (attr == null) ? def : attr.getNodeValue().charAt(0);
643
      }
644
    catch (StringIndexOutOfBoundsException e)
645
      {
646
        throw new TransformerConfigurationException("empty attribute '" +
647
                                                    name +
648
                                                    "' in decimal-format", e);
649
      }
650
  }
651
 
652
  private final String parseDFString(NamedNodeMap attrs, String name,
653
                                     String def)
654
  {
655
    Node attr = attrs.getNamedItem(name);
656
    return (attr == null) ? def : attr.getNodeValue();
657
  }
658
 
659
  /**
660
   * namespace-alias
661
   */
662
  final void parseNamespaceAlias(Node node, NamedNodeMap attrs)
663
    throws TransformerConfigurationException
664
  {
665
    String sp = getRequiredAttribute(attrs, "stylesheet-prefix", node);
666
    String rp = getRequiredAttribute(attrs, "result-prefix", node);
667
    namespaceAliases.put(sp, rp);
668
  }
669
 
670
  /**
671
   * attribute-set
672
   */
673
  final void parseAttributeSet(Node node, NamedNodeMap attrs)
674
    throws TransformerConfigurationException, XPathExpressionException
675
  {
676
    TemplateNode children = parse(node.getFirstChild());
677
    String name = getRequiredAttribute(attrs, "name", node);
678
    String uas = getAttribute(attrs, "use-attribute-sets");
679
    attributeSets.add(new AttributeSet(children, name, uas));
680
  }
681
 
682
  /**
683
   * Parse top-level elements.
684
   */
685
  void parse(Node node, boolean root)
686
    throws TransformerConfigurationException
687
  {
688
    while (node != null)
689
      {
690
        current = node;
691
        doParse(node, root);
692
        node = node.getNextSibling();
693
      }
694
  }
695
 
696
  void doParse(Node node, boolean root)
697
    throws TransformerConfigurationException
698
  {
699
    try
700
      {
701
        String namespaceUri = node.getNamespaceURI();
702
        if (XSL_NS.equals(namespaceUri) &&
703
            node.getNodeType() == Node.ELEMENT_NODE)
704
          {
705
            String name = node.getLocalName();
706
            NamedNodeMap attrs = node.getAttributes();
707
            if ("stylesheet".equals(name))
708
              {
709
                version = getAttribute(attrs, "version");
710
                String eep = getAttribute(attrs, "extension-element-prefixes");
711
                if (eep != null)
712
                  {
713
                    StringTokenizer st = new StringTokenizer(eep);
714
                    while (st.hasMoreTokens())
715
                      {
716
                        extensionElementPrefixes.add(st.nextToken());
717
                      }
718
                  }
719
                String erp = getAttribute(attrs, "exclude-result-prefixes");
720
                if (erp != null)
721
                  {
722
                    StringTokenizer st = new StringTokenizer(erp);
723
                    while (st.hasMoreTokens())
724
                      {
725
                        excludeResultPrefixes.add(st.nextToken());
726
                      }
727
                  }
728
                parse(node.getFirstChild(), false);
729
              }
730
            else if ("template".equals(name))
731
              {
732
                templates.add(parseTemplate(node, attrs));
733
              }
734
            else if ("param".equals(name) ||
735
                     "variable".equals(name))
736
              {
737
                int type = "variable".equals(name) ?
738
                  Bindings.VARIABLE : Bindings.PARAM;
739
                TemplateNode content = parse(node.getFirstChild());
740
                QName paramName =
741
                  getQName(getRequiredAttribute(attrs, "name", node));
742
                String select = getAttribute(attrs, "select");
743
                ParameterNode param;
744
                if (select != null && select.length() > 0)
745
                  {
746
                    if (content != null)
747
                      {
748
                        String msg = "parameter '" + paramName +
749
                          "' has both select and content";
750
                        DOMSourceLocator l = new DOMSourceLocator(node);
751
                        throw new TransformerConfigurationException(msg, l);
752
                      }
753
                    Expr expr = (Expr) xpath.compile(select);
754
                    param = new ParameterNode(paramName, expr, type);
755
                  }
756
                else
757
                  {
758
                    param = new ParameterNode(paramName, null, type);
759
                    param.children = content;
760
                  }
761
                variables.add(param);
762
              }
763
            else if ("include".equals(name) || "import".equals(name))
764
              {
765
                int delta = "import".equals(name) ? -1 : 0;
766
                String href = getRequiredAttribute(attrs, "href", node);
767
                Source source;
768
                synchronized (factory.resolver)
769
                  {
770
                    if (transformer != null)
771
                      {
772
                        factory.resolver
773
                          .setUserResolver(transformer.getURIResolver());
774
                        factory.resolver
775
                          .setUserListener(transformer.getErrorListener());
776
                      }
777
                    source = factory.resolver.resolve(systemId, href);
778
                  }
779
                factory.newStylesheet(source, precedence + delta, this);
780
              }
781
            else if ("output".equals(name))
782
              {
783
                parseOutput(node, attrs);
784
              }
785
            else if ("preserve-space".equals(name))
786
              {
787
                String elements =
788
                  getRequiredAttribute(attrs, "elements", node);
789
                StringTokenizer st = new StringTokenizer(elements,
790
                                                         " \t\n\r");
791
                while (st.hasMoreTokens())
792
                  {
793
                    preserveSpace.add(parseNameTest(st.nextToken()));
794
                  }
795
              }
796
            else if ("strip-space".equals(name))
797
              {
798
                String elements =
799
                  getRequiredAttribute(attrs, "elements", node);
800
                StringTokenizer st = new StringTokenizer(elements,
801
                                                         " \t\n\r");
802
                while (st.hasMoreTokens())
803
                  {
804
                    stripSpace.add(parseNameTest(st.nextToken()));
805
                  }
806
              }
807
            else if ("key".equals(name))
808
              {
809
                parseKey(node, attrs);
810
              }
811
            else if ("decimal-format".equals(name))
812
              {
813
                parseDecimalFormat(node, attrs);
814
              }
815
            else if ("namespace-alias".equals(name))
816
              {
817
                parseNamespaceAlias(node, attrs);
818
              }
819
            else if ("attribute-set".equals(name))
820
              {
821
                parseAttributeSet(node, attrs);
822
              }
823
          }
824
        else if (root)
825
          {
826
            // Literal document element
827
            Attr versionNode =
828
              ((Element)node).getAttributeNodeNS(XSL_NS, "version");
829
            if (versionNode == null)
830
              {
831
                String msg = "no xsl:version attribute on literal result node";
832
                DOMSourceLocator l = new DOMSourceLocator(node);
833
                throw new TransformerConfigurationException(msg, l);
834
              }
835
            version = versionNode.getValue();
836
            Node rootClone = node.cloneNode(true);
837
            NamedNodeMap attrs = rootClone.getAttributes();
838
            attrs.removeNamedItemNS(XSL_NS, "version");
839
            templates.add(new Template(this, null, new Root(),
840
                                       parse(rootClone),
841
                                       precedence,
842
                                       Template.DEFAULT_PRIORITY,
843
                                       null));
844
          }
845
        else
846
          {
847
            // Skip unknown elements, text, comments, etc
848
          }
849
      }
850
    catch (TransformerException e)
851
      {
852
        DOMSourceLocator l = new DOMSourceLocator(node);
853
        throw new TransformerConfigurationException(e.getMessage(), l, e);
854
      }
855
    catch (DOMException e)
856
      {
857
        DOMSourceLocator l = new DOMSourceLocator(node);
858
        throw new TransformerConfigurationException(e.getMessage(), l, e);
859
      }
860
    catch (XPathExpressionException e)
861
      {
862
        DOMSourceLocator l = new DOMSourceLocator(node);
863
        throw new TransformerConfigurationException(e.getMessage(), l, e);
864
      }
865
  }
866
 
867
  final NameTest parseNameTest(String token)
868
  {
869
    if ("*".equals(token))
870
      {
871
        return new NameTest(null, true, true);
872
      }
873
    else if (token.endsWith(":*"))
874
      {
875
        QName qName = getQName(token.substring(0, token.length() - 2));
876
        return new NameTest(qName, true, false);
877
      }
878
    else
879
      {
880
        QName qName = getQName(token);
881
        return new NameTest(qName, false, false);
882
      }
883
  }
884
 
885
  final TemplateNode parseAttributeValueTemplate(String value, Node source)
886
    throws TransformerConfigurationException, XPathExpressionException
887
  {
888
    current = source;
889
    // Tokenize
890
    int len = value.length();
891
    int off = 0;
892
    List tokens = new ArrayList(); // text tokens
893
    List types = new ArrayList(); // literal or expression
894
    int depth = 0;
895
    for (int i = 0; i < len; i++)
896
      {
897
        char c = value.charAt(i);
898
        if (c == '{')
899
          {
900
            if (i < (len - 1) && value.charAt(i + 1) == '{')
901
              {
902
                tokens.add(value.substring(off, i + 1));
903
                types.add(Boolean.FALSE);
904
                i++;
905
                off = i + 1;
906
                continue;
907
              }
908
            if (depth == 0)
909
              {
910
                if (i - off > 0)
911
                  {
912
                    tokens.add(value.substring(off, i));
913
                    types.add(Boolean.FALSE);
914
                  }
915
                off = i + 1;
916
              }
917
            depth++;
918
          }
919
        else if (c == '}')
920
          {
921
            if (i < (len - 1) && value.charAt(i + 1) == '}')
922
              {
923
                tokens.add(value.substring(off, i + 1));
924
                types.add(Boolean.FALSE);
925
                i++;
926
                off = i + 1;
927
                continue;
928
              }
929
            if (depth == 1)
930
              {
931
                if (i - off > 0)
932
                  {
933
                    tokens.add(value.substring(off, i));
934
                    types.add(Boolean.TRUE);
935
                  }
936
                else
937
                  {
938
                    String msg = "attribute value template " +
939
                      "must contain expression: " + value;
940
                    DOMSourceLocator l = new DOMSourceLocator(source);
941
                    throw new TransformerConfigurationException(msg, l);
942
                  }
943
                off = i + 1;
944
              }
945
            depth--;
946
          }
947
      }
948
    if (depth > 0)
949
      {
950
        String msg = "invalid attribute value template: " + value;
951
        throw new TransformerConfigurationException(msg);
952
      }
953
    if (len - off > 0)
954
      {
955
        // Trailing text
956
        tokens.add(value.substring(off));
957
        types.add(Boolean.FALSE);
958
      }
959
 
960
    // Construct template node tree
961
    TemplateNode ret = null;
962
    Document doc = source.getOwnerDocument();
963
    len = tokens.size();
964
    for (int i = len - 1; i >= 0; i--)
965
      {
966
        String token = (String) tokens.get(i);
967
        Boolean type = (Boolean) types.get(i);
968
        if (type == Boolean.TRUE)
969
          {
970
            // Expression text
971
            Expr select = (Expr) xpath.compile(token);
972
            TemplateNode ret2 = new ValueOfNode(select, false);
973
            ret2.next = ret;
974
            ret = ret2;
975
          }
976
        else
977
          {
978
            // Verbatim text
979
            TemplateNode ret2 = new LiteralNode(doc.createTextNode(token));
980
            ret2.next = ret;
981
            ret = ret2;
982
          }
983
      }
984
    return ret;
985
  }
986
 
987
  boolean isPreserved(Text text)
988
    throws TransformerConfigurationException
989
  {
990
    // Check characters in text
991
    String value = text.getData();
992
    if (value != null)
993
      {
994
        int len = value.length();
995
        for (int i = 0; i < len; i++)
996
          {
997
            char c = value.charAt(i);
998
            if (c != 0x20 && c != 0x09 && c != 0x0a && c != 0x0d)
999
              {
1000
                return true;
1001
              }
1002
          }
1003
      }
1004
    // Check parent node
1005
    Node ctx = text.getParentNode();
1006
    if (!preserveSpace.isEmpty())
1007
      {
1008
        for (Iterator i = preserveSpace.iterator(); i.hasNext(); )
1009
          {
1010
            NameTest preserveTest = (NameTest) i.next();
1011
            if (preserveTest.matches(ctx, 1, 1))
1012
              {
1013
                boolean override = false;
1014
                if (!stripSpace.isEmpty())
1015
                  {
1016
                    for (Iterator j = stripSpace.iterator(); j.hasNext(); )
1017
                      {
1018
                        NameTest stripTest = (NameTest) j.next();
1019
                        if (stripTest.matches(ctx, 1, 1))
1020
                          {
1021
                            override = true;
1022
                            break;
1023
                          }
1024
                      }
1025
                  }
1026
                if (!override)
1027
                  {
1028
                    return true;
1029
                  }
1030
              }
1031
          }
1032
      }
1033
    // Check whether any ancestor specified xml:space
1034
    while (ctx != null)
1035
      {
1036
        if (ctx.getNodeType() == Node.ELEMENT_NODE)
1037
          {
1038
            Element element = (Element) ctx;
1039
            String xmlSpace = element.getAttribute("xml:space");
1040
            if ("default".equals(xmlSpace))
1041
              {
1042
                break;
1043
              }
1044
            else if ("preserve".equals(xmlSpace))
1045
              {
1046
                return true;
1047
              }
1048
            else if (xmlSpace.length() > 0)
1049
              {
1050
                String msg = "Illegal value for xml:space: " + xmlSpace;
1051
                throw new TransformerConfigurationException(msg);
1052
              }
1053
            else if ("text".equals(ctx.getLocalName()) &&
1054
                     XSL_NS.equals(ctx.getNamespaceURI()))
1055
              {
1056
                // xsl:text implies xml:space='preserve'
1057
                return true;
1058
              }
1059
          }
1060
        ctx = ctx.getParentNode();
1061
      }
1062
    return false;
1063
  }
1064
 
1065
  public XPathFunction resolveFunction(QName name, int arity)
1066
  {
1067
    String uri = name.getNamespaceURI();
1068
    if (XSL_NS.equals(uri) || uri == null || uri.length() == 0)
1069
      {
1070
        String localName = name.getLocalPart();
1071
        if ("document".equals(localName) && (arity == 1 || arity == 2))
1072
          {
1073
            if (current == null)
1074
              {
1075
                throw new RuntimeException("current is null");
1076
              }
1077
            return new DocumentFunction(getRootStylesheet(), current);
1078
          }
1079
        else if ("key".equals(localName) && (arity == 2))
1080
          {
1081
            return new KeyFunction(getRootStylesheet());
1082
          }
1083
        else if ("format-number".equals(localName) &&
1084
                 (arity == 2 || arity == 3))
1085
          {
1086
            return new FormatNumberFunction(getRootStylesheet());
1087
          }
1088
        else if ("current".equals(localName) && (arity == 0))
1089
          {
1090
            return new CurrentFunction(getRootStylesheet());
1091
          }
1092
        else if ("unparsed-entity-uri".equals(localName) && (arity == 1))
1093
          {
1094
            return new UnparsedEntityUriFunction();
1095
          }
1096
        else if ("generate-id".equals(localName) &&
1097
                 (arity == 1 || arity == 0))
1098
          {
1099
            return new GenerateIdFunction();
1100
          }
1101
        else if ("system-property".equals(localName) && (arity == 1))
1102
          {
1103
            return new SystemPropertyFunction();
1104
          }
1105
        else if ("element-available".equals(localName) && (arity == 1))
1106
          {
1107
            return new ElementAvailableFunction(this);
1108
          }
1109
        else if ("function-available".equals(localName) && (arity == 1))
1110
          {
1111
            return new FunctionAvailableFunction(this);
1112
          }
1113
      }
1114
    return null;
1115
  }
1116
 
1117
  // -- Parsing --
1118
 
1119
  /**
1120
   * apply-templates
1121
   */
1122
  final TemplateNode parseApplyTemplates(Node node)
1123
    throws TransformerConfigurationException, XPathExpressionException
1124
  {
1125
    NamedNodeMap attrs = node.getAttributes();
1126
    String m = getAttribute(attrs, "mode");
1127
    QName mode = (m == null) ? null : getQName(m);
1128
    String s = getAttribute(attrs, "select");
1129
    if (s == null)
1130
      {
1131
        s = "child::node()";
1132
      }
1133
    Node children = node.getFirstChild();
1134
    List sortKeys = parseSortKeys(children);
1135
    List withParams = parseWithParams(children);
1136
    Expr select = (Expr) xpath.compile(s);
1137
    return new ApplyTemplatesNode(select, mode,
1138
                                  sortKeys, withParams, false);
1139
  }
1140
 
1141
  /**
1142
   * call-template
1143
   */
1144
  final TemplateNode parseCallTemplate(Node node)
1145
    throws TransformerConfigurationException, XPathExpressionException
1146
  {
1147
    NamedNodeMap attrs = node.getAttributes();
1148
    String n = getRequiredAttribute(attrs, "name", node);
1149
    QName name = getQName(n);
1150
    Node children = node.getFirstChild();
1151
    List withParams = parseWithParams(children);
1152
    return new CallTemplateNode(name, withParams);
1153
  }
1154
 
1155
  /**
1156
   * value-of
1157
   */
1158
  final TemplateNode parseValueOf(Node node)
1159
    throws TransformerConfigurationException, XPathExpressionException
1160
  {
1161
    NamedNodeMap attrs = node.getAttributes();
1162
    String s = getRequiredAttribute(attrs, "select", node);
1163
    String doe = getAttribute(attrs, "disable-output-escaping");
1164
    boolean d = "yes".equals(doe);
1165
    Expr select = (Expr) xpath.compile(s);
1166
    return new ValueOfNode(select, d);
1167
  }
1168
 
1169
  /**
1170
   * for-each
1171
   */
1172
  final TemplateNode parseForEach(Node node)
1173
    throws TransformerConfigurationException, XPathExpressionException
1174
  {
1175
    NamedNodeMap attrs = node.getAttributes();
1176
    String s = getRequiredAttribute(attrs, "select", node);
1177
    Node children = node.getFirstChild();
1178
    List sortKeys = parseSortKeys(children);
1179
    Expr select = (Expr) xpath.compile(s);
1180
    ForEachNode ret = new ForEachNode(select, sortKeys);
1181
    ret.children = parse(children);
1182
    return ret;
1183
  }
1184
 
1185
  /**
1186
   * if
1187
   */
1188
  final TemplateNode parseIf(Node node)
1189
    throws TransformerConfigurationException, XPathExpressionException
1190
  {
1191
    NamedNodeMap attrs = node.getAttributes();
1192
    String t = getRequiredAttribute(attrs, "test", node);
1193
    Expr test = (Expr) xpath.compile(t);
1194
    Node children = node.getFirstChild();
1195
    IfNode ret = new IfNode(test);
1196
    ret.children = parse(children);
1197
    return ret;
1198
  }
1199
 
1200
  /**
1201
   * when
1202
   */
1203
  final TemplateNode parseWhen(Node node)
1204
    throws TransformerConfigurationException, XPathExpressionException
1205
  {
1206
    NamedNodeMap attrs = node.getAttributes();
1207
    String t = getRequiredAttribute(attrs, "test", node);
1208
    Expr test = (Expr) xpath.compile(t);
1209
    Node children = node.getFirstChild();
1210
    WhenNode ret = new WhenNode(test);
1211
    ret.children = parse(children);
1212
    return ret;
1213
  }
1214
 
1215
  /**
1216
   * element
1217
   */
1218
  final TemplateNode parseElement(Node node)
1219
    throws TransformerConfigurationException, XPathExpressionException
1220
  {
1221
    NamedNodeMap attrs = node.getAttributes();
1222
    String name = getRequiredAttribute(attrs, "name", node);
1223
    String namespace = getAttribute(attrs, "namespace");
1224
    String uas = getAttribute(attrs, "use-attribute-sets");
1225
    TemplateNode n = parseAttributeValueTemplate(name, node);
1226
    TemplateNode ns = (namespace == null) ? null :
1227
      parseAttributeValueTemplate(namespace, node);
1228
    Node children = node.getFirstChild();
1229
    ElementNode ret = new ElementNode(n, ns, uas, node);
1230
    ret.children = parse(children);
1231
    return ret;
1232
  }
1233
 
1234
  /**
1235
   * attribute
1236
   */
1237
  final TemplateNode parseAttribute(Node node)
1238
    throws TransformerConfigurationException, XPathExpressionException
1239
  {
1240
    NamedNodeMap attrs = node.getAttributes();
1241
    String name = getRequiredAttribute(attrs, "name", node);
1242
    String namespace = getAttribute(attrs, "namespace");
1243
    TemplateNode n = parseAttributeValueTemplate(name, node);
1244
    TemplateNode ns = (namespace == null) ? null :
1245
      parseAttributeValueTemplate(namespace, node);
1246
    Node children = node.getFirstChild();
1247
    AttributeNode ret = new AttributeNode(n, ns, node);
1248
    ret.children = parse(children);
1249
    return ret;
1250
  }
1251
 
1252
  /**
1253
   * text
1254
   */
1255
  final TemplateNode parseText(Node node)
1256
    throws TransformerConfigurationException, XPathExpressionException
1257
  {
1258
    NamedNodeMap attrs = node.getAttributes();
1259
    String doe = getAttribute(attrs, "disable-output-escaping");
1260
    boolean d = "yes".equals(doe);
1261
    Node children = node.getFirstChild();
1262
    TextNode ret = new TextNode(d);
1263
    ret.children = parse(children);
1264
    return ret;
1265
  }
1266
 
1267
  /**
1268
   * copy
1269
   */
1270
  final TemplateNode parseCopy(Node node)
1271
    throws TransformerConfigurationException, XPathExpressionException
1272
  {
1273
    NamedNodeMap attrs = node.getAttributes();
1274
    String uas = getAttribute(attrs, "use-attribute-sets");
1275
    Node children = node.getFirstChild();
1276
    CopyNode ret = new CopyNode(uas);
1277
    ret.children = parse(children);
1278
    return ret;
1279
  }
1280
 
1281
  /**
1282
   * processing-instruction
1283
   */
1284
  final TemplateNode parseProcessingInstruction(Node node)
1285
    throws TransformerConfigurationException, XPathExpressionException
1286
  {
1287
    NamedNodeMap attrs = node.getAttributes();
1288
    String name = getRequiredAttribute(attrs, "name", node);
1289
    Node children = node.getFirstChild();
1290
    ProcessingInstructionNode ret = new ProcessingInstructionNode(name);
1291
    ret.children = parse(children);
1292
    return ret;
1293
  }
1294
 
1295
  /**
1296
   * number
1297
   */
1298
  final TemplateNode parseNumber(Node node)
1299
    throws TransformerConfigurationException, XPathExpressionException
1300
  {
1301
    NamedNodeMap attrs = node.getAttributes();
1302
    String v = getAttribute(attrs, "value");
1303
    String ff = getAttribute(attrs, "format");
1304
    if (ff == null)
1305
      {
1306
        ff = "1";
1307
      }
1308
    TemplateNode format = parseAttributeValueTemplate(ff, node);
1309
    String lang = getAttribute(attrs, "lang");
1310
    String lv = getAttribute(attrs, "letter-value");
1311
    int letterValue = "traditional".equals(lv) ?
1312
      AbstractNumberNode.TRADITIONAL :
1313
      AbstractNumberNode.ALPHABETIC;
1314
    String gs = getAttribute(attrs, "grouping-separator");
1315
    String gz = getAttribute(attrs, "grouping-size");
1316
    int gz2 = (gz != null && gz.length() > 0) ?
1317
      Integer.parseInt(gz) : 1;
1318
    Node children = node.getFirstChild();
1319
    TemplateNode ret;
1320
    if (v != null && v.length() > 0)
1321
      {
1322
        Expr value = (Expr) xpath.compile(v);
1323
        ret = new NumberNode(value, format, lang,
1324
                             letterValue, gs, gz2);
1325
      }
1326
    else
1327
      {
1328
        String l = getAttribute(attrs, "level");
1329
        int level =
1330
          "multiple".equals(l) ? NodeNumberNode.MULTIPLE :
1331
                      "any".equals(l) ? NodeNumberNode.ANY :
1332
                      NodeNumberNode.SINGLE;
1333
        String c = getAttribute(attrs, "count");
1334
        String f = getAttribute(attrs, "from");
1335
        Pattern count = null;
1336
        Pattern from = null;
1337
        if (c != null)
1338
          {
1339
            try
1340
              {
1341
                count = (Pattern) xpath.compile(c);
1342
              }
1343
            catch (ClassCastException e)
1344
              {
1345
                String msg = "invalid pattern: " + c;
1346
                throw new TransformerConfigurationException(msg);
1347
              }
1348
          }
1349
        if (f != null)
1350
          {
1351
            try
1352
              {
1353
                from = (Pattern) xpath.compile(f);
1354
              }
1355
            catch (ClassCastException e)
1356
              {
1357
                String msg = "invalid pattern: " + f;
1358
                throw new TransformerConfigurationException(msg);
1359
              }
1360
          }
1361
        ret = new NodeNumberNode(level, count, from,
1362
                                 format, lang,
1363
                                 letterValue, gs, gz2);
1364
      }
1365
    ret.children = parse(children);
1366
    return ret;
1367
  }
1368
 
1369
  /**
1370
   * copy-of
1371
   */
1372
  final TemplateNode parseCopyOf(Node node)
1373
    throws TransformerConfigurationException, XPathExpressionException
1374
  {
1375
    NamedNodeMap attrs = node.getAttributes();
1376
    String s = getRequiredAttribute(attrs, "select", node);
1377
    Expr select = (Expr) xpath.compile(s);
1378
    Node children = node.getFirstChild();
1379
    CopyOfNode ret = new CopyOfNode(select);
1380
    ret.children = parse(children);
1381
    return ret;
1382
  }
1383
 
1384
  /**
1385
   * message
1386
   */
1387
  final TemplateNode parseMessage(Node node)
1388
    throws TransformerConfigurationException, XPathExpressionException
1389
  {
1390
    NamedNodeMap attrs = node.getAttributes();
1391
    String t = getAttribute(attrs, "terminate");
1392
    boolean terminate = "yes".equals(t);
1393
    Node children = node.getFirstChild();
1394
    MessageNode ret = new MessageNode(terminate);
1395
    ret.children = parse(children);
1396
    return ret;
1397
  }
1398
 
1399
  /**
1400
   * Parse template-level elements.
1401
   */
1402
  final TemplateNode parse(Node node)
1403
    throws TransformerConfigurationException
1404
  {
1405
    TemplateNode first = null;
1406
    TemplateNode previous = null;
1407
    while (node != null)
1408
      {
1409
        Node next = node.getNextSibling();
1410
        TemplateNode tnode = doParse(node);
1411
        if (tnode != null)
1412
          {
1413
            if (first == null)
1414
              {
1415
                first = tnode;
1416
              }
1417
            if (previous != null)
1418
              {
1419
                previous.next = tnode;
1420
              }
1421
            previous = tnode;
1422
          }
1423
        node = next;
1424
      }
1425
    return first;
1426
  }
1427
 
1428
  private final TemplateNode doParse(Node node)
1429
    throws TransformerConfigurationException
1430
  {
1431
    // Hack to associate the document function with its declaring node
1432
    current = node;
1433
    try
1434
      {
1435
        String namespaceUri = node.getNamespaceURI();
1436
        if (Stylesheet.XSL_NS.equals(namespaceUri) &&
1437
            Node.ELEMENT_NODE == node.getNodeType())
1438
          {
1439
            String name = node.getLocalName();
1440
            if ("apply-templates".equals(name))
1441
              {
1442
                return parseApplyTemplates(node);
1443
              }
1444
            else if ("call-template".equals(name))
1445
              {
1446
                return parseCallTemplate(node);
1447
              }
1448
            else if ("value-of".equals(name))
1449
              {
1450
                return parseValueOf(node);
1451
              }
1452
            else if ("for-each".equals(name))
1453
              {
1454
                return parseForEach(node);
1455
              }
1456
            else if ("if".equals(name))
1457
              {
1458
                return parseIf(node);
1459
              }
1460
            else if ("choose".equals(name))
1461
              {
1462
                Node children = node.getFirstChild();
1463
                ChooseNode ret = new ChooseNode();
1464
                ret.children = parse(children);
1465
                return ret;
1466
              }
1467
            else if ("when".equals(name))
1468
              {
1469
                return parseWhen(node);
1470
              }
1471
            else if ("otherwise".equals(name))
1472
              {
1473
                Node children = node.getFirstChild();
1474
                OtherwiseNode ret = new OtherwiseNode();
1475
                ret.children = parse(children);
1476
                return ret;
1477
              }
1478
            else if ("element".equals(name))
1479
              {
1480
                return parseElement(node);
1481
              }
1482
            else if ("attribute".equals(name))
1483
              {
1484
                return parseAttribute(node);
1485
              }
1486
            else if ("text".equals(name))
1487
              {
1488
                return parseText(node);
1489
              }
1490
            else if ("copy".equals(name))
1491
              {
1492
                return parseCopy(node);
1493
              }
1494
            else if ("processing-instruction".equals(name))
1495
              {
1496
                return parseProcessingInstruction(node);
1497
              }
1498
            else if ("comment".equals(name))
1499
              {
1500
                Node children = node.getFirstChild();
1501
                CommentNode ret = new CommentNode();
1502
                ret.children = parse(children);
1503
                return ret;
1504
              }
1505
            else if ("number".equals(name))
1506
              {
1507
                return parseNumber(node);
1508
              }
1509
            else if ("param".equals(name) ||
1510
                     "variable".equals(name))
1511
              {
1512
                int type = "variable".equals(name) ?
1513
                  Bindings.VARIABLE : Bindings.PARAM;
1514
                NamedNodeMap attrs = node.getAttributes();
1515
                Node children = node.getFirstChild();
1516
                TemplateNode content = parse(children);
1517
                QName paramName =
1518
                  getQName(getRequiredAttribute(attrs, "name", node));
1519
                String select = getAttribute(attrs, "select");
1520
                ParameterNode ret;
1521
                if (select != null)
1522
                  {
1523
                    if (content != null)
1524
                      {
1525
                        String msg = "parameter '" + paramName +
1526
                          "' has both select and content";
1527
                        DOMSourceLocator l = new DOMSourceLocator(node);
1528
                        throw new TransformerConfigurationException(msg, l);
1529
                      }
1530
                    Expr expr = (Expr) xpath.compile(select);
1531
                    ret = new ParameterNode(paramName, expr, type);
1532
                  }
1533
                else
1534
                  {
1535
                    ret = new ParameterNode(paramName, null, type);
1536
                    ret.children = content;
1537
                  }
1538
                return ret;
1539
              }
1540
            else if ("copy-of".equals(name))
1541
              {
1542
                return parseCopyOf(node);
1543
              }
1544
            else if ("message".equals(name))
1545
              {
1546
                return parseMessage(node);
1547
              }
1548
            else if ("apply-imports".equals(name))
1549
              {
1550
                Node children = node.getFirstChild();
1551
                ApplyImportsNode ret = new ApplyImportsNode();
1552
                ret.children = parse(children);
1553
                return ret;
1554
              }
1555
            else
1556
              {
1557
                // xsl:fallback
1558
                // Pass over any other XSLT nodes
1559
                return null;
1560
              }
1561
          }
1562
        String prefix = node.getPrefix();
1563
        if (extensionElementPrefixes.contains(prefix))
1564
          {
1565
            // Pass over extension elements
1566
            return null;
1567
          }
1568
        switch (node.getNodeType())
1569
          {
1570
          case Node.TEXT_NODE:
1571
            // Determine whether to strip whitespace
1572
            Text text = (Text) node;
1573
            if (!isPreserved(text))
1574
              {
1575
                // Strip
1576
                /*String data = text.getData().trim();
1577
                if (data.length() > 0)
1578
                  {
1579
                    text.setData(data);
1580
                  } // else */
1581
                text.getParentNode().removeChild(text);
1582
                return null;
1583
              }
1584
            break;
1585
          case Node.COMMENT_NODE:
1586
            // Ignore comments
1587
            return null;
1588
          case Node.ELEMENT_NODE:
1589
            // Check for attribute value templates and use-attribute-sets
1590
            NamedNodeMap attrs = node.getAttributes();
1591
            boolean convert = false;
1592
            String useAttributeSets = null;
1593
            int len = attrs.getLength();
1594
            for (int i = 0; i < len; i++)
1595
              {
1596
                Node attr = attrs.item(i);
1597
                String value = attr.getNodeValue();
1598
                if (Stylesheet.XSL_NS.equals(attr.getNamespaceURI()) &&
1599
                    "use-attribute-sets".equals(attr.getLocalName()))
1600
                  {
1601
                    useAttributeSets = value;
1602
                    convert = true;
1603
                    break;
1604
                  }
1605
                int start = value.indexOf('{');
1606
                int end = value.indexOf('}');
1607
                if (start != -1 || end != -1)
1608
                  {
1609
                    convert = true;
1610
                    break;
1611
                  }
1612
              }
1613
            if (convert)
1614
              {
1615
                // Create an element-producing template node instead
1616
                // with appropriate attribute-producing child template nodes
1617
                Node children = node.getFirstChild();
1618
                TemplateNode child = parse(children);
1619
                for (int i = 0; i < len; i++)
1620
                  {
1621
                    Node attr = attrs.item(i);
1622
                    String ans = attr.getNamespaceURI();
1623
                    String aname = attr.getNodeName();
1624
                    if (Stylesheet.XSL_NS.equals(ans) &&
1625
                        "use-attribute-sets".equals(attr.getLocalName()))
1626
                      {
1627
                        continue;
1628
                      }
1629
                    String value = attr.getNodeValue();
1630
                    TemplateNode grandchild =
1631
                      parseAttributeValueTemplate(value, node);
1632
                    TemplateNode n =
1633
                      parseAttributeValueTemplate(aname, node);
1634
                    TemplateNode ns = (ans == null) ? null :
1635
                      parseAttributeValueTemplate(ans, node);
1636
                    TemplateNode newChild = new AttributeNode(n, ns, attr);
1637
                    newChild.children = grandchild;
1638
                    newChild.next = child;
1639
                    child = newChild;
1640
                  }
1641
                String ename = node.getNodeName();
1642
                TemplateNode n = parseAttributeValueTemplate(ename, node);
1643
                TemplateNode ns = (namespaceUri == null) ? null :
1644
                  parseAttributeValueTemplate(namespaceUri, node);
1645
                ElementNode ret = new ElementNode(n, ns, useAttributeSets,
1646
                                                  node);
1647
                ret.children = child;
1648
                return ret;
1649
              }
1650
            // Otherwise fall through
1651
            break;
1652
          }
1653
      }
1654
    catch (XPathExpressionException e)
1655
      {
1656
        DOMSourceLocator l = new DOMSourceLocator(node);
1657
        throw new TransformerConfigurationException(e.getMessage(), l, e);
1658
      }
1659
    Node children = node.getFirstChild();
1660
    LiteralNode ret = new LiteralNode(node);
1661
    ret.children = parse(children);
1662
    return ret;
1663
  }
1664
 
1665
  final List parseSortKeys(Node node)
1666
    throws TransformerConfigurationException, XPathExpressionException
1667
  {
1668
    List ret = new LinkedList();
1669
    while (node != null)
1670
      {
1671
        String namespaceUri = node.getNamespaceURI();
1672
        if (Stylesheet.XSL_NS.equals(namespaceUri) &&
1673
            Node.ELEMENT_NODE == node.getNodeType() &&
1674
            "sort".equals(node.getLocalName()))
1675
          {
1676
            NamedNodeMap attrs = node.getAttributes();
1677
            String s = getAttribute(attrs, "select");
1678
            if (s == null)
1679
              {
1680
                s = ".";
1681
              }
1682
            Expr select = (Expr) xpath.compile(s);
1683
            String l = getAttribute(attrs, "lang");
1684
            TemplateNode lang = (l == null) ? null :
1685
              parseAttributeValueTemplate(l, node);
1686
            String dt = getAttribute(attrs, "data-type");
1687
            TemplateNode dataType = (dt == null) ? null :
1688
              parseAttributeValueTemplate(dt, node);
1689
            String o = getAttribute(attrs, "order");
1690
            TemplateNode order = (o == null) ? null :
1691
              parseAttributeValueTemplate(o, node);
1692
            String co = getAttribute(attrs, "case-order");
1693
            TemplateNode caseOrder = (co == null) ? null :
1694
              parseAttributeValueTemplate(co, node);
1695
            ret.add(new SortKey(select, lang, dataType, order, caseOrder));
1696
          }
1697
        node = node.getNextSibling();
1698
      }
1699
    return ret.isEmpty() ? null : ret;
1700
  }
1701
 
1702
  final List parseWithParams(Node node)
1703
    throws TransformerConfigurationException, XPathExpressionException
1704
  {
1705
    List ret = new LinkedList();
1706
    while (node != null)
1707
      {
1708
        String namespaceUri = node.getNamespaceURI();
1709
        if (Stylesheet.XSL_NS.equals(namespaceUri) &&
1710
            Node.ELEMENT_NODE == node.getNodeType() &&
1711
            "with-param".equals(node.getLocalName()))
1712
          {
1713
            NamedNodeMap attrs = node.getAttributes();
1714
            TemplateNode content = parse(node.getFirstChild());
1715
            QName name =
1716
              getQName(getRequiredAttribute(attrs, "name", node));
1717
            String select = getAttribute(attrs, "select");
1718
            if (select != null)
1719
              {
1720
                if (content != null)
1721
                  {
1722
                    String msg = "parameter '" + name +
1723
                      "' has both select and content";
1724
                    DOMSourceLocator l = new DOMSourceLocator(node);
1725
                    throw new TransformerConfigurationException(msg, l);
1726
                  }
1727
                Expr expr = (Expr) xpath.compile(select);
1728
                ret.add(new WithParam(name, expr));
1729
              }
1730
            else
1731
              {
1732
                ret.add(new WithParam(name, content));
1733
              }
1734
          }
1735
        node = node.getNextSibling();
1736
      }
1737
    return ret.isEmpty() ? null : ret;
1738
  }
1739
 
1740
  /**
1741
   * Created element nodes have a copy of the namespace nodes in the
1742
   * stylesheet, except the XSLT namespace, extension namespaces, and
1743
   * exclude-result-prefixes.
1744
   */
1745
  final void addNamespaceNodes(Node source, Node target, Document doc,
1746
                               Collection elementExcludeResultPrefixes)
1747
  {
1748
    NamedNodeMap attrs = source.getAttributes();
1749
    if (attrs != null)
1750
      {
1751
        int len = attrs.getLength();
1752
        for (int i = 0; i < len; i++)
1753
          {
1754
            Node attr = attrs.item(i);
1755
            String uri = attr.getNamespaceURI();
1756
            if (uri == XMLConstants.XMLNS_ATTRIBUTE_NS_URI)
1757
              {
1758
                String prefix = attr.getLocalName();
1759
                if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix))
1760
                  {
1761
                    prefix = "#default";
1762
                  }
1763
                String ns = attr.getNodeValue();
1764
                // Should the namespace be excluded?
1765
                if (XSL_NS.equals(ns) ||
1766
                    extensionElementPrefixes.contains(prefix) ||
1767
                    elementExcludeResultPrefixes.contains(prefix) ||
1768
                    excludeResultPrefixes.contains(prefix))
1769
                  {
1770
                    continue;
1771
                  }
1772
                // Is the namespace already defined on the target?
1773
                if (prefix == "#default")
1774
                  {
1775
                    prefix = null;
1776
                  }
1777
                if (target.lookupNamespaceURI(prefix) != null)
1778
                  {
1779
                    continue;
1780
                  }
1781
                attr = attr.cloneNode(true);
1782
                attr = doc.adoptNode(attr);
1783
                target.getAttributes().setNamedItemNS(attr);
1784
              }
1785
          }
1786
      }
1787
    Node parent = source.getParentNode();
1788
    if (parent != null)
1789
      {
1790
        addNamespaceNodes(parent, target, doc, elementExcludeResultPrefixes);
1791
      }
1792
  }
1793
 
1794
  static final String getAttribute(NamedNodeMap attrs, String name)
1795
  {
1796
    Node attr = attrs.getNamedItem(name);
1797
    if (attr == null)
1798
      {
1799
        return null;
1800
      }
1801
    String ret = attr.getNodeValue();
1802
    if (ret.length() == 0)
1803
      {
1804
        return null;
1805
      }
1806
    return ret;
1807
  }
1808
 
1809
  static final String getRequiredAttribute(NamedNodeMap attrs, String name,
1810
                                           Node source)
1811
    throws TransformerConfigurationException
1812
  {
1813
    String value = getAttribute(attrs, name);
1814
    if (value == null || value.length() == 0)
1815
      {
1816
        String msg =
1817
          name + " attribute is required on " + source.getNodeName();
1818
        DOMSourceLocator l = new DOMSourceLocator(source);
1819
        throw new TransformerConfigurationException(msg, l);
1820
      }
1821
    return value;
1822
  }
1823
 
1824
  // Handle user data changes when nodes are cloned etc
1825
 
1826
  public void handle(short op, String key, Object data, Node src, Node dst)
1827
  {
1828
    dst.setUserData(key, data, this);
1829
  }
1830
 
1831
}
1832
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.