123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773 |
- /* Stylesheet.java --
- Copyright (C) 2004,2006 Free Software Foundation, Inc.
- This file is part of GNU Classpath.
- GNU Classpath is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
- GNU Classpath is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GNU Classpath; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301 USA.
- Linking this library statically or dynamically with other modules is
- making a combined work based on this library. Thus, the terms and
- conditions of the GNU General Public License cover the whole
- combination.
- As a special exception, the copyright holders of this library give you
- permission to link this library with independent modules to produce an
- executable, regardless of the license terms of these independent
- modules, and to copy and distribute the resulting executable under
- terms of your choice, provided that you also meet, for each linked
- independent module, the terms and conditions of the license of that
- module. An independent module is a module which is not derived from
- or based on this library. If you modify this library, you may extend
- this exception to your version of the library, but you are not
- obligated to do so. If you do not wish to do so, delete this
- exception statement from your version. */
- package gnu.xml.transform;
- import gnu.java.lang.CPStringBuilder;
- import java.text.DecimalFormat;
- import java.text.DecimalFormatSymbols;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.HashSet;
- import java.util.Iterator;
- import java.util.LinkedHashMap;
- import java.util.LinkedHashSet;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import java.util.StringTokenizer;
- import javax.xml.XMLConstants;
- import javax.xml.namespace.NamespaceContext;
- import javax.xml.namespace.QName;
- import javax.xml.transform.Source;
- import javax.xml.transform.TransformerConfigurationException;
- import javax.xml.transform.TransformerException;
- import javax.xml.xpath.XPathFunction;
- import javax.xml.xpath.XPathFunctionResolver;
- import javax.xml.xpath.XPathExpressionException;
- import org.w3c.dom.Attr;
- import org.w3c.dom.Document;
- import org.w3c.dom.DOMException;
- import org.w3c.dom.Element;
- import org.w3c.dom.NamedNodeMap;
- import org.w3c.dom.Node;
- import org.w3c.dom.Text;
- import org.w3c.dom.UserDataHandler;
- import gnu.xml.xpath.Expr;
- import gnu.xml.xpath.NameTest;
- import gnu.xml.xpath.NodeTypeTest;
- import gnu.xml.xpath.Pattern;
- import gnu.xml.xpath.Selector;
- import gnu.xml.xpath.Root;
- import gnu.xml.xpath.Test;
- import gnu.xml.xpath.XPathImpl;
- /**
- * An XSL stylesheet.
- *
- * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
- */
- class Stylesheet
- implements NamespaceContext, XPathFunctionResolver, UserDataHandler, Cloneable
- {
- static final String XSL_NS = "http://www.w3.org/1999/XSL/Transform";
- private static final NameTest STYLESHEET_PRESERVE_TEXT =
- new NameTest(new QName(XSL_NS, "text"), false, false);
- static final int OUTPUT_XML = 0;
- static final int OUTPUT_HTML = 1;
- static final int OUTPUT_TEXT = 2;
- final TransformerFactoryImpl factory;
- TransformerImpl transformer;
- Stylesheet parent;
- final XPathImpl xpath;
- final String systemId;
- final int precedence;
- final boolean debug;
- /**
- * Version of XSLT.
- */
- String version;
- Collection<String> extensionElementPrefixes;
- Collection<String> excludeResultPrefixes;
- /**
- * Set of element names for which we should strip whitespace.
- */
- Set<StrippingInstruction> stripSpace;
- /**
- * Set of element names for which we should preserve whitespace.
- */
- Set<StrippingInstruction> preserveSpace;
- /**
- * Output options.
- */
- Node output;
- int outputMethod;
- String outputVersion;
- String outputEncoding;
- boolean outputOmitXmlDeclaration;
- boolean outputStandalone;
- String outputPublicId;
- String outputSystemId;
- Collection<String> outputCdataSectionElements;
- boolean outputIndent;
- String outputMediaType;
- /**
- * Keys.
- */
- Collection<Key> keys;
- /**
- * Decimal formats.
- */
- Map<String,DecimalFormat> decimalFormats;
- /**
- * Namespace aliases.
- */
- Map<String,String> namespaceAliases;
- /**
- * Attribute-sets.
- */
- List<AttributeSet> attributeSets;
- /**
- * Variables.
- */
- List<ParameterNode> variables;
- /**
- * Variable and parameter bindings.
- */
- Bindings bindings;
- /**
- * Templates.
- */
- LinkedList<Template> templates;
- TemplateNode builtInNodeTemplate;
- TemplateNode builtInTextTemplate;
- /**
- * Holds the current node while parsing.
- * Necessary to associate the document function with its declaring node,
- * to resolve namespaces, and to maintain the current node for the
- * current() function.
- */
- Node current;
- /**
- * Set by a terminating message.
- */
- transient boolean terminated;
- /**
- * Current template in force.
- */
- transient Template currentTemplate;
- Stylesheet(TransformerFactoryImpl factory,
- Stylesheet parent,
- Document doc,
- String systemId,
- int precedence)
- throws TransformerConfigurationException
- {
- this.factory = factory;
- this.systemId = systemId;
- this.precedence = precedence;
- this.parent = parent;
- extensionElementPrefixes = new HashSet<String>();
- excludeResultPrefixes = new HashSet<String>();
- stripSpace = new LinkedHashSet<StrippingInstruction>();
- preserveSpace = new LinkedHashSet<StrippingInstruction>();
- outputCdataSectionElements = new LinkedHashSet<String>();
- xpath = (XPathImpl) factory.xpathFactory.newXPath();
- xpath.setNamespaceContext(this);
- if (parent == null)
- {
- bindings = new Bindings(this);
- attributeSets = new LinkedList<AttributeSet>();
- variables = new LinkedList<ParameterNode>();
- namespaceAliases = new LinkedHashMap<String,String>();
- templates = new LinkedList<Template>();
- keys = new LinkedList<Key>();
- decimalFormats = new LinkedHashMap<String,DecimalFormat>();
- initDefaultDecimalFormat();
- xpath.setXPathFunctionResolver(this);
- }
- else
- {
- /* Test for import circularity */
- for (Stylesheet ctx = this; ctx.parent != null; ctx = ctx.parent)
- {
- if (systemId != null && systemId.equals(ctx.parent.systemId))
- {
- String msg = "circularity importing " + systemId;
- throw new TransformerConfigurationException(msg);
- }
- }
- /* OK */
- Stylesheet root = getRootStylesheet();
- bindings = root.bindings;
- attributeSets = root.attributeSets;
- variables = root.variables;
- namespaceAliases = root.namespaceAliases;
- templates = root.templates;
- keys = root.keys;
- decimalFormats = root.decimalFormats;
- xpath.setXPathFunctionResolver(root);
- }
- xpath.setXPathVariableResolver(bindings);
- Test anyNode = new NodeTypeTest((short) 0);
- List<Test> tests = Collections.singletonList(anyNode);
- builtInNodeTemplate =
- new ApplyTemplatesNode(new Selector(Selector.CHILD, tests),
- null, null, null, true);
- builtInTextTemplate =
- new ValueOfNode(new Selector(Selector.SELF, tests),
- false);
- parse(doc.getDocumentElement(), true);
- current = doc; // Alow namespace resolution during processing
- debug = ("yes".equals(System.getProperty("xsl.debug")));
- if (debug)
- {
- System.err.println("Stylesheet: " + doc.getDocumentURI());
- for (Template t : templates)
- {
- t.list(System.err);
- System.err.println("--------------------");
- }
- }
- }
- Stylesheet getRootStylesheet()
- {
- Stylesheet stylesheet = this;
- while (stylesheet.parent != null)
- stylesheet = stylesheet.parent;
- return stylesheet;
- }
- void initDefaultDecimalFormat()
- {
- DecimalFormat defaultDecimalFormat = new DecimalFormat();
- DecimalFormatSymbols symbols = new DecimalFormatSymbols();
- symbols.setDecimalSeparator('.');
- symbols.setGroupingSeparator(',');
- symbols.setPercent('%');
- symbols.setPerMill('\u2030');
- symbols.setZeroDigit('0');
- symbols.setDigit('#');
- symbols.setPatternSeparator(';');
- symbols.setInfinity("Infinity");
- symbols.setNaN("NaN");
- symbols.setMinusSign('-');
- defaultDecimalFormat.setDecimalFormatSymbols(symbols);
- decimalFormats.put(null, defaultDecimalFormat);
- }
- // -- Cloneable --
- public Object clone()
- {
- try
- {
- Stylesheet clone = (Stylesheet) super.clone();
- clone.bindings = (Bindings) bindings.clone();
- LinkedList<Template> templates2 = new LinkedList<Template>();
- for (Template t : templates)
- {
- templates2.add(t.clone(clone));
- }
- clone.templates = templates2;
- LinkedList<AttributeSet> attributeSets2 = new LinkedList<AttributeSet>();
- for (AttributeSet as : attributeSets)
- {
- attributeSets2.add(as.clone(clone));
- }
- clone.attributeSets = attributeSets2;
- LinkedList<ParameterNode> variables2 = new LinkedList<ParameterNode>();
- for (ParameterNode var : variables)
- {
- variables2.add(var.clone(clone));
- }
- clone.variables = variables2;
- LinkedList<Key> keys2 = new LinkedList<Key>();
- for (Key k : keys)
- {
- keys2.add(k.clone(clone));
- }
- clone.keys = keys2;
- return clone;
- }
- catch (CloneNotSupportedException e)
- {
- throw new Error(e.getMessage());
- }
- }
- // -- Variable evaluation --
- void initTopLevelVariables(Node context)
- throws TransformerException
- {
- current = context;
- // Sort the variables into order
- // See XSLT 11.4: "If the template or expression specifying the value of
- // a global variable x references a global variable y, then the value
- // for y must be computed before the value of x."
- List<ParameterNode> topLevel = new ArrayList<ParameterNode>(variables);
- Collections.sort(topLevel);
- for (ParameterNode var : topLevel)
- {
- bindings.set(var.name,
- var.getValue(this, null, context, 1, 1),
- var.type);
- }
- current = null;
- }
- // -- NamespaceContext --
- public String getNamespaceURI(String prefix)
- {
- return (current == null) ? null : current.lookupNamespaceURI(prefix);
- }
- public String getPrefix(String namespaceURI)
- {
- return (current == null) ? null : current.lookupPrefix(namespaceURI);
- }
- public Iterator<String> getPrefixes(String namespaceURI)
- {
- // TODO
- return Collections.singleton(getPrefix(namespaceURI)).iterator();
- }
- final QName getQName(String name)
- {
- String localName = name, uri = null, prefix = null;
- int ci = name.indexOf(':');
- if (ci != -1)
- {
- prefix = name.substring(0, ci);
- localName = name.substring(ci + 1);
- uri = getNamespaceURI(prefix);
- }
- return new QName(uri, localName, prefix);
- }
- // -- Template selection --
- TemplateNode getTemplate(QName mode, Node context, boolean applyImports)
- throws TransformerException
- {
- if (debug)
- System.err.println("getTemplate: mode="+mode+" context="+context);
- Template selected = null;
- for (Template t : templates)
- {
- boolean isMatch = t.matches(mode, context);
- if (applyImports)
- {
- if (currentTemplate == null)
- {
- String msg = "current template may not be null " +
- "during apply-imports";
- throw new TransformerException(msg);
- }
- if (!currentTemplate.imports(t))
- isMatch = false;
- }
- //System.err.println("\t"+context+" "+t+"="+isMatch);
- if (isMatch)
- {
- // Conflict resolution
- // @see http://www.w3.org/TR/xslt#conflict
- if (selected == null)
- selected = t;
- else
- {
- if (t.precedence < selected.precedence ||
- t.priority < selected.priority)
- continue;
- selected = t;
- }
- }
- }
- if (selected == null)
- {
- // Apply built-in template
- // Current template is unchanged
- if (debug)
- System.err.println("\tbuiltInTemplate context="+context);
- switch (context.getNodeType())
- {
- case Node.ELEMENT_NODE:
- case Node.DOCUMENT_NODE:
- case Node.DOCUMENT_FRAGMENT_NODE:
- case Node.PROCESSING_INSTRUCTION_NODE:
- case Node.COMMENT_NODE:
- return builtInNodeTemplate;
- case Node.TEXT_NODE:
- case Node.CDATA_SECTION_NODE:
- case Node.ATTRIBUTE_NODE:
- return builtInTextTemplate;
- default:
- return null;
- }
- }
- // Set current template
- currentTemplate = selected;
- if (debug)
- System.err.println("\ttemplate="+currentTemplate+" context="+context);
- return currentTemplate.node;
- }
- TemplateNode getTemplate(QName mode, QName name)
- throws TransformerException
- {
- Template selected = null;
- for (Template t : templates)
- {
- boolean isMatch = t.matches(name);
- if (isMatch)
- {
- // Conflict resolution
- // @see http://www.w3.org/TR/xslt#conflict
- if (selected == null)
- selected = t;
- else
- {
- if (t.precedence < selected.precedence ||
- t.priority < selected.priority)
- continue;
- selected = t;
- }
- }
- }
- if (selected == null)
- return null;
- return selected.node;
- }
- /**
- * template
- */
- final Template parseTemplate(Node node, NamedNodeMap attrs)
- throws TransformerConfigurationException, XPathExpressionException
- {
- String n = getAttribute(attrs, "name");
- QName name = (n == null) ? null : getQName(n);
- String m = getAttribute(attrs, "match");
- Pattern match = null;
- if (m != null)
- {
- try
- {
- match = (Pattern) xpath.compile(m);
- }
- catch (ClassCastException e)
- {
- String msg = "illegal pattern: " + m;
- throw new TransformerConfigurationException(msg);
- }
- }
- String p = getAttribute(attrs, "priority");
- String mm = getAttribute(attrs, "mode");
- QName mode = (mm == null) ? null : getQName(mm);
- Node children = node.getFirstChild();
- return new Template(this, name, match, parse(children),
- precedence, p, mode);
- }
- /**
- * output
- */
- final void parseOutput(Node node, NamedNodeMap attrs)
- throws TransformerConfigurationException
- {
- output = node;
- String method = getAttribute(attrs, "method");
- if ("xml".equals(method) || method == null)
- outputMethod = OUTPUT_XML;
- else if ("html".equals(method))
- outputMethod = OUTPUT_HTML;
- else if ("text".equals(method))
- outputMethod = OUTPUT_TEXT;
- else
- {
- String msg = "unsupported output method: " + method;
- DOMSourceLocator l = new DOMSourceLocator(node);
- throw new TransformerConfigurationException(msg, l);
- }
- outputPublicId = getAttribute(attrs, "doctype-public");
- outputSystemId = getAttribute(attrs, "doctype-system");
- outputEncoding = getAttribute(attrs, "encoding");
- String indent = getAttribute(attrs, "indent");
- if (indent != null)
- outputIndent = "yes".equals(indent);
- outputVersion = getAttribute(attrs, "version");
- String omitXmlDecl = getAttribute(attrs, "omit-xml-declaration");
- if (omitXmlDecl != null)
- outputOmitXmlDeclaration = "yes".equals(omitXmlDecl);
- String standalone = getAttribute(attrs, "standalone");
- if (standalone != null)
- outputStandalone = "yes".equals(standalone);
- outputMediaType = getAttribute(attrs, "media-type");
- String cdataSectionElements =
- getAttribute(attrs, "cdata-section-elements");
- if (cdataSectionElements != null)
- {
- StringTokenizer st = new StringTokenizer(cdataSectionElements, " ");
- while (st.hasMoreTokens())
- outputCdataSectionElements.add(st.nextToken());
- }
- }
- /**
- * key
- */
- final void parseKey(Node node, NamedNodeMap attrs)
- throws TransformerConfigurationException, XPathExpressionException
- {
- String n = getRequiredAttribute(attrs, "name", node);
- String m = getRequiredAttribute(attrs, "match", node);
- String u = getRequiredAttribute(attrs, "use", node);
- QName name = getQName(n);
- Expr use = (Expr) xpath.compile(u);
- try
- {
- Pattern match = (Pattern) xpath.compile(m);
- Key key = new Key(name, match, use);
- keys.add(key);
- }
- catch (ClassCastException e)
- {
- throw new TransformerConfigurationException("invalid pattern: " + m);
- }
- }
- /**
- * decimal-format
- */
- final void parseDecimalFormat(Node node, NamedNodeMap attrs)
- throws TransformerConfigurationException
- {
- String dfName = getAttribute(attrs, "name");
- DecimalFormat df = new DecimalFormat();
- DecimalFormatSymbols symbols = new DecimalFormatSymbols();
- symbols.setDecimalSeparator(parseDFChar(attrs, "decimal-separator", '.'));
- symbols.setGroupingSeparator(parseDFChar(attrs, "grouping-separator", ','));
- symbols.setInfinity(parseDFString(attrs, "infinity", "Infinity"));
- symbols.setMinusSign(parseDFChar(attrs, "minus-sign", '-'));
- symbols.setNaN(parseDFString(attrs, "NaN", "NaN"));
- symbols.setPercent(parseDFChar(attrs, "percent", '%'));
- symbols.setPerMill(parseDFChar(attrs, "per-mille", '\u2030'));
- symbols.setZeroDigit(parseDFChar(attrs, "zero-digit", '0'));
- symbols.setDigit(parseDFChar(attrs, "digit", '#'));
- symbols.setPatternSeparator(parseDFChar(attrs, "pattern-separator", ';'));
- df.setDecimalFormatSymbols(symbols);
- decimalFormats.put(dfName, df);
- }
- private final char parseDFChar(NamedNodeMap attrs, String name, char def)
- throws TransformerConfigurationException
- {
- Node attr = attrs.getNamedItem(name);
- try
- {
- return (attr == null) ? def : attr.getNodeValue().charAt(0);
- }
- catch (StringIndexOutOfBoundsException e)
- {
- throw new TransformerConfigurationException("empty attribute '" +
- name +
- "' in decimal-format", e);
- }
- }
- private final String parseDFString(NamedNodeMap attrs, String name,
- String def)
- {
- Node attr = attrs.getNamedItem(name);
- return (attr == null) ? def : attr.getNodeValue();
- }
- /**
- * namespace-alias
- */
- final void parseNamespaceAlias(Node node, NamedNodeMap attrs)
- throws TransformerConfigurationException
- {
- String sp = getRequiredAttribute(attrs, "stylesheet-prefix", node);
- String rp = getRequiredAttribute(attrs, "result-prefix", node);
- namespaceAliases.put(sp, rp);
- }
- /**
- * attribute-set
- */
- final void parseAttributeSet(Node node, NamedNodeMap attrs)
- throws TransformerConfigurationException, XPathExpressionException
- {
- TemplateNode children = parse(node.getFirstChild());
- String name = getRequiredAttribute(attrs, "name", node);
- String uas = getAttribute(attrs, "use-attribute-sets");
- attributeSets.add(new AttributeSet(children, name, uas));
- }
- /**
- * Parse top-level elements.
- */
- void parse(Node node, boolean root)
- throws TransformerConfigurationException
- {
- while (node != null)
- {
- current = node;
- doParse(node, root);
- node = node.getNextSibling();
- }
- }
- void doParse(Node node, boolean root)
- throws TransformerConfigurationException
- {
- try
- {
- String namespaceUri = node.getNamespaceURI();
- if (XSL_NS.equals(namespaceUri) &&
- node.getNodeType() == Node.ELEMENT_NODE)
- {
- String name = node.getLocalName();
- NamedNodeMap attrs = node.getAttributes();
- if ("stylesheet".equals(name))
- {
- version = getAttribute(attrs, "version");
- String eep = getAttribute(attrs, "extension-element-prefixes");
- if (eep != null)
- {
- StringTokenizer st = new StringTokenizer(eep);
- while (st.hasMoreTokens())
- {
- extensionElementPrefixes.add(st.nextToken());
- }
- }
- String erp = getAttribute(attrs, "exclude-result-prefixes");
- if (erp != null)
- {
- StringTokenizer st = new StringTokenizer(erp);
- while (st.hasMoreTokens())
- {
- excludeResultPrefixes.add(st.nextToken());
- }
- }
- parse(node.getFirstChild(), false);
- }
- else if ("template".equals(name))
- templates.add(parseTemplate(node, attrs));
- else if ("param".equals(name) ||
- "variable".equals(name))
- {
- int type = "variable".equals(name) ?
- Bindings.VARIABLE : Bindings.PARAM;
- TemplateNode content = parse(node.getFirstChild());
- QName paramName =
- getQName(getRequiredAttribute(attrs, "name", node));
- String select = getAttribute(attrs, "select");
- ParameterNode param;
- if (select != null && select.length() > 0)
- {
- if (content != null)
- {
- String msg = "parameter '" + paramName +
- "' has both select and content";
- DOMSourceLocator l = new DOMSourceLocator(node);
- throw new TransformerConfigurationException(msg, l);
- }
- Expr expr = (Expr) xpath.compile(select);
- param = new ParameterNode(paramName, expr, type);
- }
- else
- {
- param = new ParameterNode(paramName, null, type);
- param.children = content;
- }
- variables.add(param);
- }
- else if ("include".equals(name) || "import".equals(name))
- {
- int delta = "import".equals(name) ? -1 : 0;
- String href = getRequiredAttribute(attrs, "href", node);
- Source source;
- synchronized (factory.resolver)
- {
- if (transformer != null)
- {
- factory.resolver
- .setUserResolver(transformer.getURIResolver());
- factory.resolver
- .setUserListener(transformer.getErrorListener());
- }
- source = factory.resolver.resolve(systemId, href);
- }
- factory.newStylesheet(source, precedence + delta, this);
- }
- else if ("output".equals(name))
- parseOutput(node, attrs);
- else if ("preserve-space".equals(name))
- {
- String elements =
- getRequiredAttribute(attrs, "elements", node);
- StringTokenizer st = new StringTokenizer(elements,
- " \t\n\r");
- while (st.hasMoreTokens())
- {
- NameTest element = parseNameTest(st.nextToken());
- preserveSpace.add(new StrippingInstruction(element,
- precedence));
- }
- }
- else if ("strip-space".equals(name))
- {
- String elements =
- getRequiredAttribute(attrs, "elements", node);
- StringTokenizer st = new StringTokenizer(elements,
- " \t\n\r");
- while (st.hasMoreTokens())
- {
- NameTest element = parseNameTest(st.nextToken());
- stripSpace.add(new StrippingInstruction(element,
- precedence));
- }
- }
- else if ("key".equals(name))
- parseKey(node, attrs);
- else if ("decimal-format".equals(name))
- parseDecimalFormat(node, attrs);
- else if ("namespace-alias".equals(name))
- parseNamespaceAlias(node, attrs);
- else if ("attribute-set".equals(name))
- parseAttributeSet(node, attrs);
- }
- else if (root)
- {
- // Literal document element
- Attr versionNode =
- ((Element)node).getAttributeNodeNS(XSL_NS, "version");
- if (versionNode == null)
- {
- String msg = "no xsl:version attribute on literal result node";
- DOMSourceLocator l = new DOMSourceLocator(node);
- throw new TransformerConfigurationException(msg, l);
- }
- version = versionNode.getValue();
- Node rootClone = node.cloneNode(true);
- NamedNodeMap attrs = rootClone.getAttributes();
- attrs.removeNamedItemNS(XSL_NS, "version");
- templates.add(new Template(this, null, new Root(),
- parse(rootClone),
- precedence,
- null,
- null));
- }
- else
- {
- // Skip unknown elements, text, comments, etc
- }
- }
- catch (TransformerException e)
- {
- DOMSourceLocator l = new DOMSourceLocator(node);
- throw new TransformerConfigurationException(e.getMessage(), l, e);
- }
- catch (DOMException e)
- {
- DOMSourceLocator l = new DOMSourceLocator(node);
- throw new TransformerConfigurationException(e.getMessage(), l, e);
- }
- catch (XPathExpressionException e)
- {
- DOMSourceLocator l = new DOMSourceLocator(node);
- throw new TransformerConfigurationException(e.getMessage(), l, e);
- }
- }
- final NameTest parseNameTest(String token)
- {
- if ("*".equals(token))
- return new NameTest(null, true, true);
- else if (token.endsWith(":*"))
- {
- QName qName = getQName(token);
- return new NameTest(qName, true, false);
- }
- else
- {
- QName qName = getQName(token);
- return new NameTest(qName, false, false);
- }
- }
- final TemplateNode parseAttributeValueTemplate(String value, Node source)
- throws TransformerConfigurationException, XPathExpressionException
- {
- current = source;
- // Tokenize
- int len = value.length();
- int off = 0;
- List<String> tokens = new ArrayList<String>(); // text tokens
- List<Boolean> types = new ArrayList<Boolean>(); // literal or expression
- int depth = 0;
- for (int i = 0; i < len; i++)
- {
- char c = value.charAt(i);
- if (c == '{')
- {
- if (i < (len - 1) && value.charAt(i + 1) == '{')
- {
- tokens.add(value.substring(off, i + 1));
- types.add(Boolean.FALSE);
- i++;
- off = i + 1;
- continue;
- }
- if (depth == 0)
- {
- if (i - off > 0)
- {
- tokens.add(value.substring(off, i));
- types.add(Boolean.FALSE);
- }
- off = i + 1;
- }
- depth++;
- }
- else if (c == '}')
- {
- if (i < (len - 1) && value.charAt(i + 1) == '}')
- {
- tokens.add(value.substring(off, i + 1));
- types.add(Boolean.FALSE);
- i++;
- off = i + 1;
- continue;
- }
- if (depth == 1)
- {
- if (i - off > 0)
- {
- tokens.add(value.substring(off, i));
- types.add(Boolean.TRUE);
- }
- else
- {
- String msg = "attribute value template " +
- "must contain expression: " + value;
- DOMSourceLocator l = new DOMSourceLocator(source);
- throw new TransformerConfigurationException(msg, l);
- }
- off = i + 1;
- }
- depth--;
- }
- }
- if (depth > 0)
- {
- String msg = "invalid attribute value template: " + value;
- throw new TransformerConfigurationException(msg);
- }
- if (len - off > 0)
- {
- // Trailing text
- tokens.add(value.substring(off));
- types.add(Boolean.FALSE);
- }
- // Construct template node tree
- TemplateNode ret = null;
- Document doc = source.getOwnerDocument();
- len = tokens.size();
- for (int i = len - 1; i >= 0; i--)
- {
- String token = tokens.get(i);
- Boolean type = types.get(i);
- if (type == Boolean.TRUE)
- {
- // Expression text
- Expr select = (Expr) xpath.compile(token);
- TemplateNode ret2 = new ValueOfNode(select, false);
- ret2.next = ret;
- ret = ret2;
- }
- else
- {
- // Verbatim text
- TemplateNode ret2 = new LiteralNode(doc.createTextNode(token));
- ret2.next = ret;
- ret = ret2;
- }
- }
- return ret;
- }
- /**
- * Whitespace stripping.
- * @param text the text node
- * @param source true if a source node, false if a stylesheet text node
- * @see http://www.w3.org/TR/xslt#strip
- */
- boolean isPreserved(Text text, boolean source)
- throws TransformerConfigurationException
- {
- // Check characters in text
- String value = text.getData();
- if (value != null)
- {
- int len = value.length();
- for (int i = 0; i < len; i++)
- {
- char c = value.charAt(i);
- if (c != 0x20 && c != 0x09 && c != 0x0a && c != 0x0d)
- return true;
- }
- }
- // Check parent node
- Node ctx = text.getParentNode();
- if (source)
- {
- // Source document text node
- boolean preserve = true;
- float psPriority = 0.0f, ssPriority = 0.0f;
- if (!stripSpace.isEmpty())
- {
- // Conflict resolution
- StrippingInstruction ssi = null, psi = null;
- for (StrippingInstruction si : stripSpace)
- {
- if (si.element.matches(ctx, 1, 1))
- {
- if (ssi != null)
- {
- if (si.precedence < ssi.precedence)
- continue;
- float p = si.getPriority();
- if (p < ssPriority)
- continue;
- }
- ssi = si;
- }
- }
- for (StrippingInstruction si : preserveSpace)
- {
- if (si.element.matches(ctx, 1, 1))
- {
- if (psi != null)
- {
- if (si.precedence < psi.precedence)
- continue;
- float p = si.getPriority();
- if (p < psPriority)
- continue;
- }
- psi = si;
- }
- }
- if (ssi != null)
- {
- if (psi != null)
- {
- if (psi.precedence < ssi.precedence)
- preserve = false;
- else if (psPriority < ssPriority)
- preserve = false;
- }
- else
- preserve = false;
- }
- }
- if (preserve)
- return true;
- }
- else
- {
- // Stylesheet text node
- if (STYLESHEET_PRESERVE_TEXT.matches(ctx, 1, 1))
- return true;
- }
- // Check whether any ancestor specified xml:space
- while (ctx != null)
- {
- if (ctx.getNodeType() == Node.ELEMENT_NODE)
- {
- Element element = (Element) ctx;
- String xmlSpace = element.getAttribute("xml:space");
- if ("default".equals(xmlSpace))
- break;
- else if ("preserve".equals(xmlSpace))
- return true;
- else if (xmlSpace.length() > 0)
- {
- String msg = "Illegal value for xml:space: " + xmlSpace;
- throw new TransformerConfigurationException(msg);
- }
- }
- ctx = ctx.getParentNode();
- }
- return false;
- }
- public XPathFunction resolveFunction(QName name, int arity)
- {
- String uri = name.getNamespaceURI();
- if (XSL_NS.equals(uri) || uri == null || uri.length() == 0)
- {
- String localName = name.getLocalPart();
- if ("document".equals(localName) && (arity == 1 || arity == 2))
- {
- if (current == null)
- throw new RuntimeException("current is null");
- return new DocumentFunction(getRootStylesheet(), current);
- }
- else if ("key".equals(localName) && (arity == 2))
- return new KeyFunction(getRootStylesheet());
- else if ("format-number".equals(localName) &&
- (arity == 2 || arity == 3))
- return new FormatNumberFunction(getRootStylesheet());
- else if ("current".equals(localName) && (arity == 0))
- return new CurrentFunction(getRootStylesheet());
- else if ("unparsed-entity-uri".equals(localName) && (arity == 1))
- return new UnparsedEntityUriFunction();
- else if ("generate-id".equals(localName) &&
- (arity == 1 || arity == 0))
- return new GenerateIdFunction();
- else if ("system-property".equals(localName) && (arity == 1))
- return new SystemPropertyFunction();
- else if ("element-available".equals(localName) && (arity == 1))
- return new ElementAvailableFunction(new NamespaceProxy(current));
- else if ("function-available".equals(localName) && (arity == 1))
- return new FunctionAvailableFunction(new NamespaceProxy(current));
- }
- return null;
- }
- // -- Parsing --
- /**
- * apply-templates
- */
- final TemplateNode parseApplyTemplates(Node node)
- throws TransformerConfigurationException, XPathExpressionException
- {
- NamedNodeMap attrs = node.getAttributes();
- String m = getAttribute(attrs, "mode");
- QName mode = (m == null) ? null : getQName(m);
- String s = getAttribute(attrs, "select");
- if (s == null)
- s = "child::node()";
- Node children = node.getFirstChild();
- List<SortKey> sortKeys = parseSortKeys(children);
- List<WithParam> withParams = parseWithParams(children);
- Expr select = (Expr) xpath.compile(s);
- return new ApplyTemplatesNode(select, mode,
- sortKeys, withParams, false);
- }
- /**
- * call-template
- */
- final TemplateNode parseCallTemplate(Node node)
- throws TransformerConfigurationException, XPathExpressionException
- {
- NamedNodeMap attrs = node.getAttributes();
- String n = getRequiredAttribute(attrs, "name", node);
- QName name = getQName(n);
- Node children = node.getFirstChild();
- List<WithParam> withParams = parseWithParams(children);
- return new CallTemplateNode(name, withParams);
- }
- /**
- * value-of
- */
- final TemplateNode parseValueOf(Node node)
- throws TransformerConfigurationException, XPathExpressionException
- {
- NamedNodeMap attrs = node.getAttributes();
- String s = getRequiredAttribute(attrs, "select", node);
- String doe = getAttribute(attrs, "disable-output-escaping");
- boolean d = "yes".equals(doe);
- Expr select = (Expr) xpath.compile(s);
- return new ValueOfNode(select, d);
- }
- /**
- * for-each
- */
- final TemplateNode parseForEach(Node node)
- throws TransformerConfigurationException, XPathExpressionException
- {
- NamedNodeMap attrs = node.getAttributes();
- String s = getRequiredAttribute(attrs, "select", node);
- Node children = node.getFirstChild();
- List<SortKey> sortKeys = parseSortKeys(children);
- Expr select = (Expr) xpath.compile(s);
- ForEachNode ret = new ForEachNode(select, sortKeys);
- ret.children = parse(children);
- return ret;
- }
- /**
- * if
- */
- final TemplateNode parseIf(Node node)
- throws TransformerConfigurationException, XPathExpressionException
- {
- NamedNodeMap attrs = node.getAttributes();
- String t = getRequiredAttribute(attrs, "test", node);
- Expr test = (Expr) xpath.compile(t);
- Node children = node.getFirstChild();
- IfNode ret = new IfNode(test);
- ret.children = parse(children);
- return ret;
- }
- /**
- * when
- */
- final TemplateNode parseWhen(Node node)
- throws TransformerConfigurationException, XPathExpressionException
- {
- NamedNodeMap attrs = node.getAttributes();
- String t = getRequiredAttribute(attrs, "test", node);
- Expr test = (Expr) xpath.compile(t);
- Node children = node.getFirstChild();
- WhenNode ret = new WhenNode(test);
- ret.children = parse(children);
- return ret;
- }
- /**
- * element
- */
- final TemplateNode parseElement(Node node)
- throws TransformerConfigurationException, XPathExpressionException
- {
- NamedNodeMap attrs = node.getAttributes();
- String name = getRequiredAttribute(attrs, "name", node);
- String namespace = getAttribute(attrs, "namespace");
- String uas = getAttribute(attrs, "use-attribute-sets");
- TemplateNode n = parseAttributeValueTemplate(name, node);
- TemplateNode ns = (namespace == null) ? null :
- parseAttributeValueTemplate(namespace, node);
- Node children = node.getFirstChild();
- ElementNode ret = new ElementNode(n, ns, uas, node);
- ret.children = parse(children);
- return ret;
- }
- /**
- * attribute
- */
- final TemplateNode parseAttribute(Node node)
- throws TransformerConfigurationException, XPathExpressionException
- {
- NamedNodeMap attrs = node.getAttributes();
- String name = getRequiredAttribute(attrs, "name", node);
- String namespace = getAttribute(attrs, "namespace");
- TemplateNode n = parseAttributeValueTemplate(name, node);
- TemplateNode ns = (namespace == null) ? null :
- parseAttributeValueTemplate(namespace, node);
- Node children = node.getFirstChild();
- AttributeNode ret = new AttributeNode(n, ns, node);
- ret.children = parse(children);
- return ret;
- }
- /**
- * text
- */
- final TemplateNode parseText(Node node)
- throws TransformerConfigurationException, XPathExpressionException
- {
- NamedNodeMap attrs = node.getAttributes();
- String doe = getAttribute(attrs, "disable-output-escaping");
- boolean d = "yes".equals(doe);
- Node children = node.getFirstChild();
- TextNode ret = new TextNode(d);
- ret.children = parse(children);
- return ret;
- }
- /**
- * copy
- */
- final TemplateNode parseCopy(Node node)
- throws TransformerConfigurationException, XPathExpressionException
- {
- NamedNodeMap attrs = node.getAttributes();
- String uas = getAttribute(attrs, "use-attribute-sets");
- Node children = node.getFirstChild();
- CopyNode ret = new CopyNode(uas);
- ret.children = parse(children);
- return ret;
- }
- /**
- * processing-instruction
- */
- final TemplateNode parseProcessingInstruction(Node node)
- throws TransformerConfigurationException, XPathExpressionException
- {
- NamedNodeMap attrs = node.getAttributes();
- String name = getRequiredAttribute(attrs, "name", node);
- Node children = node.getFirstChild();
- ProcessingInstructionNode ret = new ProcessingInstructionNode(name);
- ret.children = parse(children);
- return ret;
- }
- /**
- * number
- */
- final TemplateNode parseNumber(Node node)
- throws TransformerConfigurationException, XPathExpressionException
- {
- NamedNodeMap attrs = node.getAttributes();
- String v = getAttribute(attrs, "value");
- String ff = getAttribute(attrs, "format");
- if (ff == null)
- {
- ff = "1";
- }
- TemplateNode format = parseAttributeValueTemplate(ff, node);
- String lang = getAttribute(attrs, "lang");
- String lv = getAttribute(attrs, "letter-value");
- int letterValue = "traditional".equals(lv) ?
- AbstractNumberNode.TRADITIONAL :
- AbstractNumberNode.ALPHABETIC;
- String gs = getAttribute(attrs, "grouping-separator");
- String gz = getAttribute(attrs, "grouping-size");
- int gz2 = (gz != null && gz.length() > 0) ?
- Integer.parseInt(gz) : 1;
- Node children = node.getFirstChild();
- TemplateNode ret;
- if (v != null && v.length() > 0)
- {
- Expr value = (Expr) xpath.compile(v);
- ret = new NumberNode(value, format, lang,
- letterValue, gs, gz2);
- }
- else
- {
- String l = getAttribute(attrs, "level");
- int level =
- "multiple".equals(l) ? NodeNumberNode.MULTIPLE :
- "any".equals(l) ? NodeNumberNode.ANY :
- NodeNumberNode.SINGLE;
- String c = getAttribute(attrs, "count");
- String f = getAttribute(attrs, "from");
- Pattern count = null;
- Pattern from = null;
- if (c != null)
- {
- try
- {
- count = (Pattern) xpath.compile(c);
- }
- catch (ClassCastException e)
- {
- String msg = "invalid pattern: " + c;
- throw new TransformerConfigurationException(msg);
- }
- }
- if (f != null)
- {
- try
- {
- from = (Pattern) xpath.compile(f);
- }
- catch (ClassCastException e)
- {
- String msg = "invalid pattern: " + f;
- throw new TransformerConfigurationException(msg);
- }
- }
- ret = new NodeNumberNode(level, count, from,
- format, lang,
- letterValue, gs, gz2);
- }
- ret.children = parse(children);
- return ret;
- }
- /**
- * copy-of
- */
- final TemplateNode parseCopyOf(Node node)
- throws TransformerConfigurationException, XPathExpressionException
- {
- NamedNodeMap attrs = node.getAttributes();
- String s = getRequiredAttribute(attrs, "select", node);
- Expr select = (Expr) xpath.compile(s);
- Node children = node.getFirstChild();
- CopyOfNode ret = new CopyOfNode(select);
- ret.children = parse(children);
- return ret;
- }
- /**
- * message
- */
- final TemplateNode parseMessage(Node node)
- throws TransformerConfigurationException, XPathExpressionException
- {
- NamedNodeMap attrs = node.getAttributes();
- String t = getAttribute(attrs, "terminate");
- boolean terminate = "yes".equals(t);
- Node children = node.getFirstChild();
- MessageNode ret = new MessageNode(terminate);
- ret.children = parse(children);
- return ret;
- }
- /**
- * Parse template-level elements.
- */
- final TemplateNode parse(Node node)
- throws TransformerConfigurationException
- {
- TemplateNode first = null;
- TemplateNode previous = null;
- while (node != null)
- {
- Node next = node.getNextSibling();
- TemplateNode tnode = doParse(node);
- if (tnode != null)
- {
- if (first == null)
- first = tnode;
- if (previous != null)
- previous.next = tnode;
- previous = tnode;
- }
- node = next;
- }
- return first;
- }
- private final TemplateNode doParse(Node node)
- throws TransformerConfigurationException
- {
- // Hack to associate the document function with its declaring node
- current = node;
- try
- {
- String namespaceUri = node.getNamespaceURI();
- if (Stylesheet.XSL_NS.equals(namespaceUri) &&
- Node.ELEMENT_NODE == node.getNodeType())
- {
- String name = node.getLocalName();
- if ("apply-templates".equals(name))
- return parseApplyTemplates(node);
- else if ("call-template".equals(name))
- return parseCallTemplate(node);
- else if ("value-of".equals(name))
- return parseValueOf(node);
- else if ("for-each".equals(name))
- return parseForEach(node);
- else if ("if".equals(name))
- return parseIf(node);
- else if ("choose".equals(name))
- {
- Node children = node.getFirstChild();
- ChooseNode ret = new ChooseNode();
- ret.children = parse(children);
- return ret;
- }
- else if ("when".equals(name))
- return parseWhen(node);
- else if ("otherwise".equals(name))
- {
- Node children = node.getFirstChild();
- OtherwiseNode ret = new OtherwiseNode();
- ret.children = parse(children);
- return ret;
- }
- else if ("element".equals(name))
- return parseElement(node);
- else if ("attribute".equals(name))
- return parseAttribute(node);
- else if ("text".equals(name))
- return parseText(node);
- else if ("copy".equals(name))
- return parseCopy(node);
- else if ("processing-instruction".equals(name))
- return parseProcessingInstruction(node);
- else if ("comment".equals(name))
- {
- Node children = node.getFirstChild();
- CommentNode ret = new CommentNode();
- ret.children = parse(children);
- return ret;
- }
- else if ("number".equals(name))
- return parseNumber(node);
- else if ("param".equals(name) ||
- "variable".equals(name))
- {
- int type = "variable".equals(name) ?
- Bindings.VARIABLE : Bindings.PARAM;
- NamedNodeMap attrs = node.getAttributes();
- Node children = node.getFirstChild();
- TemplateNode content = parse(children);
- QName paramName =
- getQName(getRequiredAttribute(attrs, "name", node));
- String select = getAttribute(attrs, "select");
- ParameterNode ret;
- if (select != null)
- {
- if (content != null)
- {
- String msg = "parameter '" + paramName +
- "' has both select and content";
- DOMSourceLocator l = new DOMSourceLocator(node);
- throw new TransformerConfigurationException(msg, l);
- }
- Expr expr = (Expr) xpath.compile(select);
- ret = new ParameterNode(paramName, expr, type);
- }
- else
- {
- ret = new ParameterNode(paramName, null, type);
- ret.children = content;
- }
- return ret;
- }
- else if ("copy-of".equals(name))
- return parseCopyOf(node);
- else if ("message".equals(name))
- return parseMessage(node);
- else if ("apply-imports".equals(name))
- {
- Node children = node.getFirstChild();
- ApplyImportsNode ret = new ApplyImportsNode();
- ret.children = parse(children);
- return ret;
- }
- else
- {
- // xsl:fallback
- // Pass over any other XSLT nodes
- return null;
- }
- }
- String prefix = node.getPrefix();
- if (extensionElementPrefixes.contains(prefix))
- {
- // Check for xsl:fallback
- for (Node ctx = node.getFirstChild(); ctx != null;
- ctx = ctx.getNextSibling())
- {
- String ctxUri = ctx.getNamespaceURI();
- if (XSL_NS.equals(ctxUri) &&
- "fallback".equals(ctx.getLocalName()))
- {
- ctx = ctx.getFirstChild();
- return (ctx == null) ? null : parse(ctx);
- }
- }
- // Otherwise pass over extension element
- return null;
- }
- switch (node.getNodeType())
- {
- case Node.TEXT_NODE:
- case Node.CDATA_SECTION_NODE:
- // Determine whether to strip whitespace
- Text text = (Text) node;
- if (!isPreserved(text, false))
- {
- // Strip
- text.getParentNode().removeChild(text);
- return null;
- }
- break;
- case Node.COMMENT_NODE:
- // Ignore comments
- return null;
- case Node.ELEMENT_NODE:
- // Check for attribute value templates and use-attribute-sets
- NamedNodeMap attrs = node.getAttributes();
- boolean convert = false;
- String useAttributeSets = null;
- int len = attrs.getLength();
- for (int i = 0; i < len; i++)
- {
- Node attr = attrs.item(i);
- String value = attr.getNodeValue();
- if (Stylesheet.XSL_NS.equals(attr.getNamespaceURI()) &&
- "use-attribute-sets".equals(attr.getLocalName()))
- {
- useAttributeSets = value;
- convert = true;
- break;
- }
- int start = value.indexOf('{');
- int end = value.indexOf('}');
- if (start != -1 || end != -1)
- {
- convert = true;
- break;
- }
- }
- if (convert)
- {
- // Create an element-producing template node instead
- // with appropriate attribute-producing child template nodes
- Node children = node.getFirstChild();
- TemplateNode child = parse(children);
- for (int i = 0; i < len; i++)
- {
- Node attr = attrs.item(i);
- String ans = attr.getNamespaceURI();
- String aname = attr.getNodeName();
- if (Stylesheet.XSL_NS.equals(ans) &&
- "use-attribute-sets".equals(attr.getLocalName()))
- continue;
- String value = attr.getNodeValue();
- TemplateNode grandchild =
- parseAttributeValueTemplate(value, node);
- TemplateNode n =
- parseAttributeValueTemplate(aname, node);
- TemplateNode ns = (ans == null) ? null :
- parseAttributeValueTemplate(ans, node);
- TemplateNode newChild = new AttributeNode(n, ns, attr);
- newChild.children = grandchild;
- newChild.next = child;
- child = newChild;
- }
- String ename = node.getNodeName();
- TemplateNode n = parseAttributeValueTemplate(ename, node);
- //TemplateNode ns = (namespaceUri == null) ? null :
- // parseAttributeValueTemplate(namespaceUri, node);
- TemplateNode ns = null;
- ElementNode ret = new ElementNode(n, ns, useAttributeSets,
- node);
- ret.children = child;
- return ret;
- }
- // Otherwise fall through
- break;
- }
- }
- catch (XPathExpressionException e)
- {
- DOMSourceLocator l = new DOMSourceLocator(node);
- throw new TransformerConfigurationException(e.getMessage(), l, e);
- }
- Node children = node.getFirstChild();
- LiteralNode ret = new LiteralNode(node);
- ret.children = parse(children);
- return ret;
- }
- final List<SortKey> parseSortKeys(Node node)
- throws TransformerConfigurationException, XPathExpressionException
- {
- List<SortKey> ret = new LinkedList<SortKey>();
- while (node != null)
- {
- String namespaceUri = node.getNamespaceURI();
- if (Stylesheet.XSL_NS.equals(namespaceUri) &&
- Node.ELEMENT_NODE == node.getNodeType() &&
- "sort".equals(node.getLocalName()))
- {
- NamedNodeMap attrs = node.getAttributes();
- String s = getAttribute(attrs, "select");
- if (s == null)
- s = ".";
- Expr select = (Expr) xpath.compile(s);
- String l = getAttribute(attrs, "lang");
- TemplateNode lang = (l == null) ? null :
- parseAttributeValueTemplate(l, node);
- String dt = getAttribute(attrs, "data-type");
- TemplateNode dataType = (dt == null) ? null :
- parseAttributeValueTemplate(dt, node);
- String o = getAttribute(attrs, "order");
- TemplateNode order = (o == null) ? null :
- parseAttributeValueTemplate(o, node);
- String co = getAttribute(attrs, "case-order");
- TemplateNode caseOrder = (co == null) ? null :
- parseAttributeValueTemplate(co, node);
- ret.add(new SortKey(select, lang, dataType, order, caseOrder));
- }
- node = node.getNextSibling();
- }
- return ret;
- }
- final List<WithParam> parseWithParams(Node node)
- throws TransformerConfigurationException, XPathExpressionException
- {
- List<WithParam> ret = new LinkedList<WithParam>();
- while (node != null)
- {
- String namespaceUri = node.getNamespaceURI();
- if (Stylesheet.XSL_NS.equals(namespaceUri) &&
- Node.ELEMENT_NODE == node.getNodeType() &&
- "with-param".equals(node.getLocalName()))
- {
- NamedNodeMap attrs = node.getAttributes();
- TemplateNode content = parse(node.getFirstChild());
- QName name =
- getQName(getRequiredAttribute(attrs, "name", node));
- String select = getAttribute(attrs, "select");
- if (select != null)
- {
- if (content != null)
- {
- String msg = "parameter '" + name +
- "' has both select and content";
- DOMSourceLocator l = new DOMSourceLocator(node);
- throw new TransformerConfigurationException(msg, l);
- }
- Expr expr = (Expr) xpath.compile(select);
- ret.add(new WithParam(name, expr));
- }
- else
- ret.add(new WithParam(name, content));
- }
- node = node.getNextSibling();
- }
- return ret;
- }
- /**
- * Created element nodes have a copy of the namespace nodes in the
- * stylesheet, except the XSLT namespace, extension namespaces, and
- * exclude-result-prefixes.
- */
- final void addNamespaceNodes(Node source, Node target, Document doc,
- Collection<String> elementExcludeResultPrefixes)
- {
- NamedNodeMap attrs = source.getAttributes();
- if (attrs != null)
- {
- int len = attrs.getLength();
- for (int i = 0; i < len; i++)
- {
- Node attr = attrs.item(i);
- String uri = attr.getNamespaceURI();
- if (uri == XMLConstants.XMLNS_ATTRIBUTE_NS_URI)
- {
- String prefix = attr.getLocalName();
- if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix))
- prefix = "#default";
- String ns = attr.getNodeValue();
- // Should the namespace be excluded?
- if (XSL_NS.equals(ns) ||
- extensionElementPrefixes.contains(prefix) ||
- elementExcludeResultPrefixes.contains(prefix) ||
- excludeResultPrefixes.contains(prefix))
- continue;
- // Is the namespace already defined on the target?
- if (prefix == "#default")
- prefix = null;
- if (target.lookupNamespaceURI(prefix) != null)
- continue;
- attr = attr.cloneNode(true);
- attr = doc.adoptNode(attr);
- target.getAttributes().setNamedItemNS(attr);
- }
- }
- }
- Node parent = source.getParentNode();
- if (parent != null)
- addNamespaceNodes(parent, target, doc, elementExcludeResultPrefixes);
- }
- static final String getAttribute(NamedNodeMap attrs, String name)
- {
- Node attr = attrs.getNamedItem(name);
- if (attr == null)
- return null;
- String ret = attr.getNodeValue();
- if (ret.length() == 0)
- return null;
- return ret;
- }
- static final String getRequiredAttribute(NamedNodeMap attrs, String name,
- Node source)
- throws TransformerConfigurationException
- {
- String value = getAttribute(attrs, name);
- if (value == null || value.length() == 0)
- {
- String msg =
- name + " attribute is required on " + source.getNodeName();
- DOMSourceLocator l = new DOMSourceLocator(source);
- throw new TransformerConfigurationException(msg, l);
- }
- return value;
- }
- // Handle user data changes when nodes are cloned etc
- public void handle(short op, String key, Object data, Node src, Node dst)
- {
- dst.setUserData(key, data, this);
- }
- public String toString()
- {
- CPStringBuilder b = new CPStringBuilder(getClass().getName());
- b.append("[templates=");
- b.append(templates);
- b.append("]");
- return b.toString();
- }
- }
|