Initial revision

From-SVN: r102074
This commit is contained in:
Tom Tromey
2005-07-16 00:30:23 +00:00
parent 6f4434b39b
commit f911ba985a
4557 changed files with 1000262 additions and 0 deletions
@@ -0,0 +1,328 @@
/* AbstractNumberNode.java --
Copyright (C) 2004 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 java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
import gnu.xml.xpath.Expr;
/**
* A template node representing the XSL <code>number</code> instruction.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
abstract class AbstractNumberNode
extends TemplateNode
{
static final int ALPHABETIC = 0;
static final int TRADITIONAL = 1;
final TemplateNode format;
final String lang;
final int letterValue;
final String groupingSeparator;
final int groupingSize;
AbstractNumberNode(TemplateNode format, String lang,
int letterValue, String groupingSeparator,
int groupingSize)
{
this.format = format;
this.lang = lang;
this.letterValue = letterValue;
this.groupingSeparator = groupingSeparator;
this.groupingSize = groupingSize;
}
void doApply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
Document doc = (parent instanceof Document) ? (Document) parent :
parent.getOwnerDocument();
DocumentFragment fragment = doc.createDocumentFragment();
format.apply(stylesheet, mode, context, pos, len, fragment, null);
String f = Expr._string(context, Collections.singleton(fragment));
String value = format(f, compute(stylesheet, context, pos, len));
Text text = doc.createTextNode(value);
if (nextSibling != null)
{
parent.insertBefore(text, nextSibling);
}
else
{
parent.appendChild(text);
}
// xsl:number doesn't process children
if (next != null)
{
next.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
}
String format(String format, int[] number)
{
if (number.length == 0)
{
return "";
}
int start = 0, end = 0, len = format.length(); // region of format
// Tokenize
List tokens = new ArrayList((number.length * 2) + 1);
List types = new ArrayList(tokens.size());
while (end < len)
{
while (end < len && !isAlphanumeric(format.charAt(end)))
{
end++;
}
if (end > start)
{
tokens.add(format.substring(start, end));
types.add(Boolean.FALSE);
}
start = end;
while (end < len && isAlphanumeric(format.charAt(end)))
{
end++;
}
if (end > start)
{
tokens.add(format.substring(start, end));
types.add(Boolean.TRUE);
}
start = end;
}
// Process tokens
StringBuffer buf = new StringBuffer();
len = tokens.size();
int pos = 0;
for (int i = 0; i < len; i++)
{
String token = (i < 0) ? "." : (String) tokens.get(i);
boolean alpha = (i < 0) ? true :
((Boolean) types.get(i)).booleanValue();
if (!alpha)
{
buf.append(token);
}
else
{
if (pos < number.length)
{
format(buf, number[pos++], token);
if (((i + 1 == len) || (i + 2 == len)) &&
(pos < number.length))
{
// More numbers than tokens, reuse last token
i -= 2;
}
}
if (pos == number.length && i < (len - 2))
{
// No more numbers. Skip to the end...
i = len - 2;
if (((Boolean) types.get(i + 1)).booleanValue())
{
// number formatting token, ignore
i++;
}
}
}
}
//System.err.println("format: '"+format+"' "+asList(number)+" = '"+buf.toString()+"'");
return buf.toString();
}
/*List asList(int[] number)
{
List l = new ArrayList();
for (int i = 0; i < number.length; i++)
l.add(new Integer(number[i]));
return l;
}*/
void format(StringBuffer buf, int number, String formatToken)
{
int len = formatToken.length();
char c = formatToken.charAt(len - 1);
if (Character.digit(c, 10) == 1)
{
// Check preceding characters
for (int i = len - 2; i >= 0; i--)
{
if (formatToken.charAt(i) != (c - 1))
{
format(buf, number, "1");
return;
}
}
// Decimal representation
String val = Integer.toString(number);
for (int d = len - val.length(); d > 0; d--)
{
buf.append('0');
}
buf.append(val);
}
else if ("A".equals(formatToken))
{
buf.append(alphabetic('@', number));
}
else if ("a".equals(formatToken))
{
buf.append(alphabetic('`', number));
}
else if ("i".equals(formatToken))
{
buf.append(roman(false, number));
}
else if ("I".equals(formatToken))
{
buf.append(roman(true, number));
}
else
{
// Unknown numbering sequence
format(buf, number, "1");
}
}
static final boolean isAlphanumeric(char c)
{
switch (Character.getType(c))
{
case Character.DECIMAL_DIGIT_NUMBER: // Nd
case Character.LETTER_NUMBER: // Nl
case Character.OTHER_NUMBER: // No
case Character.UPPERCASE_LETTER: // Lu
case Character.LOWERCASE_LETTER: // Ll
case Character.TITLECASE_LETTER: // Lt
case Character.MODIFIER_LETTER: // Lm
case Character.OTHER_LETTER: // Lo
return true;
default:
return false;
}
}
static final String alphabetic(char offset, int number)
{
StringBuffer buf = new StringBuffer();
while (number > 0)
{
int r = number % 26;
number = number / 26;
buf.insert(0, (char) (offset + r));
}
return buf.toString();
}
static final int[] roman_numbers = {1, 5, 10, 50, 100, 500, 1000};
static final char[] roman_chars = {'i', 'v', 'x', 'l', 'c', 'd', 'm'};
static final String roman(boolean upper, int number)
{
StringBuffer buf = new StringBuffer();
for (int pos = roman_numbers.length - 1; pos >= 0; pos -= 2)
{
int f = number / roman_numbers[pos];
if (f != 0)
{
number = number % (f * roman_numbers[pos]);
}
if (f > 4 && f < 9)
{
buf.append(roman_chars[pos + 1]);
f -= 5;
}
if (f == 4)
{
buf.append(roman_chars[pos]);
buf.append(roman_chars[pos + 1]);
}
else if (f == 9)
{
buf.append(roman_chars[pos]);
buf.append(roman_chars[pos + 2]);
}
else
{
for (; f > 0; f--)
{
buf.append(roman_chars[pos]);
}
}
}
return upper ? buf.toString().toUpperCase() : buf.toString();
}
abstract int[] compute(Stylesheet stylesheet, Node context, int pos, int len)
throws TransformerException;
public boolean references(QName var)
{
if (format.references(var))
{
return true;
}
return super.references(var);
}
public String toString()
{
StringBuffer buf = new StringBuffer(getClass().getName());
buf.append('[');
buf.append("format=");
buf.append(format);
buf.append(']');
return buf.toString();
}
}
@@ -0,0 +1,86 @@
/* ApplyImportsNode.java --
Copyright (C) 2004 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 javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Node;
/**
* A template node representing an XSLT <code>apply-imports</code> instruction.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class ApplyImportsNode
extends TemplateNode
{
TemplateNode clone(Stylesheet stylesheet)
{
TemplateNode ret = new ApplyImportsNode();
if (children != null)
{
ret.children = children.clone(stylesheet);
}
if (next != null)
{
ret.next = next.clone(stylesheet);
}
return ret;
}
void doApply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
TemplateNode t = stylesheet.getTemplate(mode, context, true);
if (t != null)
{
t.apply(stylesheet, mode, context, pos, len,
parent, nextSibling);
}
if (next != null)
{
next.apply(stylesheet, mode, context, pos, len,
parent, nextSibling);
}
}
}
@@ -0,0 +1,235 @@
/* ApplyTemplatesNode.java --
Copyright (C) 2004 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 java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
/**
* A template node representing the XSL <code>apply-templates</code>
* instruction.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class ApplyTemplatesNode
extends TemplateNode
{
final Expr select;
final QName mode;
final List sortKeys;
final List withParams;
final boolean isDefault;
ApplyTemplatesNode(Expr select, QName mode,
List sortKeys, List withParams, boolean isDefault)
{
this.select = select;
this.mode = mode;
this.sortKeys = sortKeys;
this.withParams = withParams;
this.isDefault = isDefault;
}
TemplateNode clone(Stylesheet stylesheet)
{
int len = sortKeys.size();
List sortKeys2 = new ArrayList(len);
for (int i = 0; i < len; i++)
{
sortKeys2.add(((Key) sortKeys.get(i)).clone(stylesheet));
}
len = withParams.size();
List withParams2 = new ArrayList(len);
for (int i = 0; i < len; i++)
{
withParams2.add(((WithParam) withParams.get(i)).clone(stylesheet));
}
TemplateNode ret = new ApplyTemplatesNode(select.clone(stylesheet),
mode, sortKeys2, withParams2,
isDefault);
if (children != null)
{
ret.children = children.clone(stylesheet);
}
if (next != null)
{
ret.next = next.clone(stylesheet);
}
return ret;
}
void doApply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
Object ret = select.evaluate(context, pos, len);
if (ret != null && ret instanceof Collection)
{
if (withParams != null)
{
// compute the parameter values
LinkedList values = new LinkedList();
for (Iterator i = withParams.iterator(); i.hasNext(); )
{
WithParam p = (WithParam) i.next();
Object value = p.getValue(stylesheet, mode, context, pos, len);
Object[] pair = new Object[2];
pair[0] = p.name;
pair[1] = value;
values.add(pair);
}
// push the parameter context
stylesheet.bindings.push(Bindings.WITH_PARAM);
// set the parameters
for (Iterator i = values.iterator(); i.hasNext(); )
{
Object[] pair = (Object[]) i.next();
QName name = (QName) pair[0];
Object value = pair[1];
stylesheet.bindings.set(name, value, Bindings.WITH_PARAM);
}
}
Collection ns = (Collection) ret;
List nodes = new ArrayList(ns);
if (sortKeys != null)
{
for (Iterator i = sortKeys.iterator(); i.hasNext(); )
{
SortKey sortKey = (SortKey) i.next();
sortKey.init(stylesheet, mode, context, pos, len, parent,
nextSibling);
}
Collections.sort(nodes, new XSLComparator(sortKeys));
}
else
{
Collections.sort(nodes, documentOrderComparator);
}
int l = nodes.size();
QName effectiveMode = isDefault ? mode : this.mode;
for (int i = 0; i < l; i++)
{
Node node = (Node) nodes.get(i);
TemplateNode t = stylesheet.getTemplate(effectiveMode, node,
false);
if (t != null)
{
stylesheet.current = node;
t.apply(stylesheet, effectiveMode, node, i + 1, l,
parent, nextSibling);
}
}
if (withParams != null)
{
// pop the variable context
stylesheet.bindings.pop(Bindings.WITH_PARAM);
}
}
// apply-templates doesn't have processable children
if (next != null)
{
next.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
}
public boolean references(QName var)
{
if (select != null && select.references(var))
{
return true;
}
if (withParams != null)
{
for (Iterator i = withParams.iterator(); i.hasNext(); )
{
if (((WithParam) i.next()).references(var))
{
return true;
}
}
}
if (sortKeys != null)
{
for (Iterator i = sortKeys.iterator(); i.hasNext(); )
{
if (((SortKey) i.next()).references(var))
{
return true;
}
}
}
return super.references(var);
}
public String toString()
{
StringBuffer buf = new StringBuffer(getClass().getName());
buf.append('[');
boolean o = false;
if (select != null)
{
buf.append("select=");
buf.append(select);
o = true;
}
if (mode != null)
{
if (o)
{
buf.append(',');
}
buf.append("mode=");
buf.append(mode);
}
buf.append(']');
return buf.toString();
}
}
@@ -0,0 +1,264 @@
/* AttributeNode.java --
Copyright (C) 2004 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 javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Attr;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
/**
* A template node representing an XSL <code>attribute</code> instruction.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class AttributeNode
extends TemplateNode
{
final TemplateNode name;
final TemplateNode namespace;
final Node source;
AttributeNode(TemplateNode name,
TemplateNode namespace, Node source)
{
this.name = name;
this.namespace = namespace;
this.source = source;
}
TemplateNode clone(Stylesheet stylesheet)
{
TemplateNode ret = new AttributeNode(name.clone(stylesheet),
(namespace == null) ? null :
namespace.clone(stylesheet),
source);
if (children != null)
{
ret.children = children.clone(stylesheet);
}
if (next != null)
{
ret.next = next.clone(stylesheet);
}
return ret;
}
void doApply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
Document doc = (parent instanceof Document) ? (Document) parent :
parent.getOwnerDocument();
// Create a document fragment to hold the name
DocumentFragment fragment = doc.createDocumentFragment();
// Apply name to the fragment
name.apply(stylesheet, mode,
context, pos, len,
fragment, null);
// Use XPath string-value of fragment
String nameValue = Expr.stringValue(fragment);
String namespaceValue = null;
if (namespace != null)
{
// Create a document fragment to hold the namespace
fragment = doc.createDocumentFragment();
// Apply namespace to the fragment
namespace.apply(stylesheet, mode,
context, pos, len,
fragment, null);
// Use XPath string-value of fragment
namespaceValue = Expr.stringValue(fragment);
if (namespaceValue.length() == 0)
{
namespaceValue = null;
}
}
String prefix = getPrefix(nameValue);
if (namespaceValue == null)
{
if (prefix != null)
{
if (XMLConstants.XML_NS_PREFIX.equals(prefix))
{
namespaceValue = XMLConstants.XML_NS_URI;
}
else
{
// Resolve namespace for this prefix
namespaceValue = source.lookupNamespaceURI(prefix);
}
}
}
else
{
if (prefix != null)
{
String ns2 = source.lookupNamespaceURI(prefix);
if (ns2 != null && !ns2.equals(namespaceValue))
{
// prefix clashes, reset it
prefix = null;
int ci = nameValue.indexOf(':');
nameValue = nameValue.substring(ci + 1);
}
}
}
if (prefix == null)
{
// Resolve prefix for this namespace
prefix = source.lookupPrefix(namespaceValue);
if (prefix != null)
{
nameValue = prefix + ":" + nameValue;
}
else
{
if (namespaceValue != null)
{
// Must invent a prefix
prefix = inventPrefix(parent);
nameValue = prefix + ":" + nameValue;
}
}
}
NamedNodeMap attrs = parent.getAttributes();
boolean insert = true;
if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceValue) ||
XMLConstants.XMLNS_ATTRIBUTE.equals(nameValue) ||
nameValue.startsWith("xmlns:"))
{
// Namespace declaration, do not output
insert = false;
}
if (prefix != null && namespaceValue == null)
{
// Not a QName
insert = false;
}
if (parent.getNodeType() == Node.ELEMENT_NODE &&
parent.getFirstChild() != null)
{
// XSLT 7.1.3 Adding an attribute to an element after children have
// been added to it is an error
insert = false;
}
if (insert)
{
// Insert attribute
Attr attr = (namespaceValue != null) ?
doc.createAttributeNS(namespaceValue, nameValue) :
doc.createAttribute(nameValue);
if (attrs != null)
{
if (namespace != null)
{
attrs.setNamedItemNS(attr);
}
else
{
attrs.setNamedItem(attr);
}
}
if (children != null)
{
children.apply(stylesheet, mode,
context, pos, len,
attr, null);
}
}
if (next != null)
{
next.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
}
final String getPrefix(String name)
{
int ci = name.indexOf(':');
return (ci == -1) ? null : name.substring(0, ci);
}
final String inventPrefix(Node parent)
{
String base = "ns";
int count = 0;
String ret = base + Integer.toString(count);
while (parent.lookupNamespaceURI(ret) != null)
{
count++;
ret = base + Integer.toString(count);
}
return ret;
}
public boolean references(QName var)
{
if (name != null && name.references(var))
{
return true;
}
if (namespace != null && namespace.references(var))
{
return true;
}
return super.references(var);
}
public String toString()
{
StringBuffer buf = new StringBuffer(getClass().getName());
buf.append('[');
buf.append("name=");
buf.append(name);
buf.append(']');
return buf.toString();
}
}
@@ -0,0 +1,67 @@
/* AttributeSet.java --
Copyright (C) 2004 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;
/**
* An attribute-set entry in a stylesheet.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class AttributeSet
{
final TemplateNode children;
final String name;
final String uas;
AttributeSet(TemplateNode children, String name, String uas)
{
this.children = children;
this.name = name;
this.uas = uas;
}
AttributeSet clone(Stylesheet stylesheet)
{
return new AttributeSet((children == null) ? null :
children.clone(stylesheet),
name, uas);
}
}
@@ -0,0 +1,325 @@
/* Bindings.java --
Copyright (C) 2004 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 java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.xpath.XPathVariableResolver;
import org.w3c.dom.Node;
/**
* The set of variable bindings in effect for a stylesheet.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
public class Bindings
implements XPathVariableResolver, Cloneable
{
static final int VARIABLE = 0;
static final int PARAM = 1;
static final int WITH_PARAM = 2;
final Stylesheet stylesheet;
/**
* Global variables.
*/
final LinkedList variables;
/**
* Parameter value stack.
*/
final LinkedList parameters;
/**
* Argument (with-param) value stack.
*/
final LinkedList withParameters;
Bindings(Stylesheet stylesheet)
{
this.stylesheet = stylesheet;
variables = new LinkedList();
parameters = new LinkedList();
withParameters = new LinkedList();
for (int i = 0; i < 3; i++)
{
push(i);
}
}
public Object clone()
{
try
{
return (Bindings) super.clone();
}
catch (CloneNotSupportedException e)
{
throw new Error(e.getMessage());
}
}
void push(int type)
{
switch (type)
{
case VARIABLE:
variables.addFirst(new HashMap());
break;
case PARAM:
parameters.addFirst(new HashMap());
break;
case WITH_PARAM:
withParameters.addFirst(new HashMap());
break;
}
}
void pop(int type)
{
switch (type)
{
case VARIABLE:
variables.removeFirst();
break;
case PARAM:
parameters.removeFirst();
break;
case WITH_PARAM:
withParameters.removeFirst();
break;
}
}
public boolean containsKey(QName name, int type)
{
Iterator i = null;
switch (type)
{
case VARIABLE:
i = variables.iterator();
break;
case PARAM:
i = parameters.iterator();
break;
case WITH_PARAM:
Map ctx = (Map) withParameters.getFirst();
return ctx.containsKey(name);
}
if (i != null)
{
while (i.hasNext())
{
Map ctx = (Map) i.next();
if (ctx.containsKey(name))
{
return true;
}
}
}
return false;
}
public Object get(QName name, Node context, int pos, int len)
{
//System.err.println("bindings.get: "+name);
//System.err.println("\t"+toString());
Object ret = null;
//if (parameters.size() > 1 && containsKey(name, PARAM))
// check that template defines parameter
{
Map cwp = (Map) withParameters.getFirst();
ret = cwp.get(name);
//System.err.println("\twith-param: ret="+ret);
}
if (ret == null)
{
for (Iterator i = variables.iterator(); i.hasNext() && ret == null; )
{
Map vctx = (Map) i.next();
ret = vctx.get(name);
}
//System.err.println("\tvariable: ret="+ret);
}
if (ret == null)
{
for (Iterator i = parameters.iterator(); i.hasNext() && ret == null; )
{
Map pctx = (Map) i.next();
ret = pctx.get(name);
}
//System.err.println("\tparam: ret="+ret);
}
/*if (ret instanceof Expr && context != null)
{
Expr expr = (Expr) ret;
ret = expr.evaluate(context, 1, 1);
}*/
if (ret instanceof Node)
{
ret = Collections.singleton(ret);
}
if (ret == null)
{
ret = "";
}
//System.err.println("\tret="+ret);
return ret;
}
void set(QName name, Object value, int type)
{
switch (type)
{
case VARIABLE:
Map vctx = (Map) variables.getFirst();
vctx.put(name, value);
break;
case PARAM:
Map pctx = (Map) parameters.getFirst();
pctx.put(name, value);
break;
case WITH_PARAM:
Map wctx = (Map) withParameters.getFirst();
wctx.put(name, value);
break;
}
//System.err.println("Set "+name+"="+value);
}
public Object resolveVariable(QName qName)
{
return get(qName, null, 1, 1);
}
public String toString()
{
StringBuffer buf = new StringBuffer();
boolean next = false;
Collection seen = new HashSet();
Map wctx = (Map) withParameters.getFirst();
buf.append('(');
for (Iterator i = wctx.entrySet().iterator(); i.hasNext(); )
{
if (next)
{
buf.append(',');
}
else
{
next = true;
}
Map.Entry entry = (Map.Entry) i.next();
Object key = entry.getKey();
if (!seen.contains(key))
{
buf.append(key);
buf.append('=');
buf.append(entry.getValue());
seen.add(key);
}
}
buf.append(')');
next = false;
seen.clear();
buf.append('{');
for (Iterator i = variables.iterator(); i.hasNext(); )
{
Map ctx = (Map) i.next();
for (Iterator j = ctx.entrySet().iterator(); j.hasNext(); )
{
if (next)
{
buf.append(',');
}
else
{
next = true;
}
Map.Entry entry = (Map.Entry) j.next();
Object key = entry.getKey();
if (!seen.contains(key))
{
buf.append(key);
buf.append('=');
buf.append(entry.getValue());
seen.add(key);
}
}
}
buf.append('}');
next = false;
seen.clear();
buf.append('[');
for (Iterator i = parameters.iterator(); i.hasNext(); )
{
Map ctx = (Map) i.next();
for (Iterator j = ctx.entrySet().iterator(); j.hasNext(); )
{
if (next)
{
buf.append(',');
}
else
{
next = true;
}
Map.Entry entry = (Map.Entry) j.next();
Object key = entry.getKey();
if (!seen.contains(key))
{
buf.append(key);
buf.append('=');
buf.append(entry.getValue());
seen.add(key);
}
}
}
buf.append(']');
return buf.toString();
}
}
@@ -0,0 +1,165 @@
/* CallTemplateNode.java --
Copyright (C) 2004 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 java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Node;
/**
* A template node representing the XSL <code>call-template</code>
* instruction.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class CallTemplateNode
extends TemplateNode
{
final QName name;
final List withParams;
CallTemplateNode(QName name, List withParams)
{
this.name = name;
this.withParams = withParams;
}
TemplateNode clone(Stylesheet stylesheet)
{
int len = withParams.size();
List withParams2 = new ArrayList(len);
for (int i = 0; i < len; i++)
{
withParams2.add(((WithParam) withParams.get(i)).clone(stylesheet));
}
TemplateNode ret = new CallTemplateNode(name, withParams2);
if (children != null)
{
ret.children = children.clone(stylesheet);
}
if (next != null)
{
ret.next = next.clone(stylesheet);
}
return ret;
}
void doApply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
if (withParams != null)
{
// compute the parameter values
LinkedList values = new LinkedList();
for (Iterator i = withParams.iterator(); i.hasNext(); )
{
WithParam p = (WithParam) i.next();
Object value = p.getValue(stylesheet, mode, context, pos, len);
Object[] pair = new Object[2];
pair[0] = p.name;
pair[1] = value;
values.add(pair);
}
// push the parameter context
stylesheet.bindings.push(Bindings.WITH_PARAM);
// set the parameters
for (Iterator i = values.iterator(); i.hasNext(); )
{
Object[] pair = (Object[]) i.next();
QName name = (QName) pair[0];
Object value = pair[1];
stylesheet.bindings.set(name, value, Bindings.WITH_PARAM);
if (stylesheet.debug)
{
System.err.println("with-param: " + name + " = " + value);
}
}
}
TemplateNode t = stylesheet.getTemplate(mode, name);
if (t != null)
{
t.apply(stylesheet, mode, context, pos, len,
parent, nextSibling);
}
if (withParams != null)
{
// pop the variable context
stylesheet.bindings.pop(Bindings.WITH_PARAM);
}
// call-template doesn't have processable children
if (next != null)
{
next.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
}
public boolean references(QName var)
{
if (withParams != null)
{
for (Iterator i = withParams.iterator(); i.hasNext(); )
{
if (((WithParam) i.next()).references(var))
{
return true;
}
}
}
return super.references(var);
}
public String toString()
{
StringBuffer buf = new StringBuffer(getClass().getName());
buf.append('[');
buf.append("name=");
buf.append(name);
buf.append(']');
return buf.toString();
}
}
@@ -0,0 +1,94 @@
/* ChooseNode.java --
Copyright (C) 2004 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 javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Node;
/**
* A template node representing an XSL <code>choose</code> instruction.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class ChooseNode
extends TemplateNode
{
TemplateNode clone(Stylesheet stylesheet)
{
TemplateNode ret = new ChooseNode();
if (children != null)
{
ret.children = children.clone(stylesheet);
}
if (next != null)
{
ret.next = next.clone(stylesheet);
}
return ret;
}
void doApply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
if (children != null)
{
children.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
if (next != null)
{
next.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
}
public String toString()
{
StringBuffer buf = new StringBuffer(getClass().getName());
buf.append('[');
buf.append(']');
return buf.toString();
}
}
@@ -0,0 +1,116 @@
/* CommentNode.java --
Copyright (C) 2004 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 javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
/**
* A template node representing the XSL <code>comment</code> instruction.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class CommentNode
extends TemplateNode
{
TemplateNode clone(Stylesheet stylesheet)
{
TemplateNode ret = new CommentNode();
if (children != null)
{
ret.children = children.clone(stylesheet);
}
if (next != null)
{
ret.next = next.clone(stylesheet);
}
return ret;
}
void doApply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
String value = "";
Document doc = (parent instanceof Document) ? (Document) parent :
parent.getOwnerDocument();
if (children != null)
{
// Create a document fragment to hold the text
DocumentFragment fragment = doc.createDocumentFragment();
// Apply children to the fragment
children.apply(stylesheet, mode,
context, pos, len,
fragment, null);
// Use XPath string-value of fragment
value = Expr.stringValue(fragment);
}
Comment comment = doc.createComment(value);
// Insert into result tree
if (nextSibling != null)
{
parent.insertBefore(comment, nextSibling);
}
else
{
parent.appendChild(comment);
}
if (next != null)
{
next.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
}
public String toString()
{
StringBuffer buf = new StringBuffer(getClass().getName());
buf.append('[');
buf.append(']');
return buf.toString();
}
}
@@ -0,0 +1,183 @@
/* CopyNode.java --
Copyright (C) 2004 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 java.util.Iterator;
import java.util.StringTokenizer;
import javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
/**
* A template node representing the XSL <code>copy</code> instruction.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class CopyNode
extends TemplateNode
{
final String uas;
CopyNode(String uas)
{
this.uas = uas;
}
TemplateNode clone(Stylesheet stylesheet)
{
TemplateNode ret = new CopyNode(uas);
if (children != null)
{
ret.children = children.clone(stylesheet);
}
if (next != null)
{
ret.next = next.clone(stylesheet);
}
return ret;
}
void doApply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
Node copy = parent;
switch (context.getNodeType())
{
case Node.TEXT_NODE:
case Node.ATTRIBUTE_NODE:
case Node.ELEMENT_NODE:
case Node.PROCESSING_INSTRUCTION_NODE:
case Node.COMMENT_NODE:
Document doc = (parent instanceof Document) ? (Document) parent :
parent.getOwnerDocument();
copy = context.cloneNode(false);
copy = doc.adoptNode(copy);
if (copy.getNodeType() == Node.ATTRIBUTE_NODE)
{
if (parent.getFirstChild() != null)
{
// Ignore attempt to add attribute after children
}
else
{
NamedNodeMap attrs = parent.getAttributes();
if (attrs != null)
{
attrs.setNamedItemNS(copy);
}
}
}
else
{
if (nextSibling != null)
{
parent.insertBefore(copy, nextSibling);
}
else
{
parent.appendChild(copy);
}
}
}
if (uas != null)
{
StringTokenizer st = new StringTokenizer(uas, " ");
while (st.hasMoreTokens())
{
addAttributeSet(stylesheet, mode, context, pos, len,
copy, null, st.nextToken());
}
}
if (children != null)
{
children.apply(stylesheet, mode,
context, pos, len,
copy, null);
}
if (next != null)
{
next.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
}
void addAttributeSet(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling, String attributeSet)
throws TransformerException
{
for (Iterator i = stylesheet.attributeSets.iterator(); i.hasNext(); )
{
AttributeSet as = (AttributeSet) i.next();
if (!as.name.equals(attributeSet))
{
continue;
}
if (as.uas != null)
{
StringTokenizer st = new StringTokenizer(as.uas, " ");
while (st.hasMoreTokens())
{
addAttributeSet(stylesheet, mode, context, pos, len,
parent, nextSibling, st.nextToken());
}
}
if (as.children != null)
{
as.children.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
}
}
public String toString()
{
StringBuffer buf = new StringBuffer(getClass().getName());
buf.append('[');
buf.append(']');
return buf.toString();
}
}
@@ -0,0 +1,192 @@
/* CopyOfNode.java --
Copyright (C) 2004 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 java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
import gnu.xml.xpath.Expr;
/**
* A template node representing an XSLT <code>copy-of</code> instruction.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class CopyOfNode
extends TemplateNode
{
final Expr select;
CopyOfNode(Expr select)
{
this.select = select;
}
TemplateNode clone(Stylesheet stylesheet)
{
TemplateNode ret = new CopyOfNode(select.clone(stylesheet));
if (children != null)
{
ret.children = children.clone(stylesheet);
}
if (next != null)
{
ret.next = next.clone(stylesheet);
}
return ret;
}
void doApply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
Object ret = select.evaluate(context, pos, len);
Document doc = (parent instanceof Document) ? (Document) parent :
parent.getOwnerDocument();
if (ret instanceof Collection)
{
Collection ns = (Collection) ret;
List list = new ArrayList(ns);
Collections.sort(list, documentOrderComparator);
for (Iterator i = list.iterator(); i.hasNext(); )
{
Node src = (Node) i.next();
short nodeType = src.getNodeType();
if (nodeType == Node.DOCUMENT_NODE)
{
// Use document element
src = ((Document) src).getDocumentElement();
if (src == null)
{
continue;
}
nodeType = Node.ELEMENT_NODE;
}
else if (nodeType == Node.ATTRIBUTE_NODE)
{
if (parent.getFirstChild() != null)
{
// Ignore attempt to add attribute after children
continue;
}
}
if (parent.getNodeType() == Node.ATTRIBUTE_NODE &&
nodeType != Node.TEXT_NODE &&
nodeType != Node.ENTITY_REFERENCE_NODE)
{
// Ignore
continue;
}
Node node = src.cloneNode(true);
node = doc.adoptNode(node);
if (nodeType == Node.ATTRIBUTE_NODE)
{
NamedNodeMap attrs = parent.getAttributes();
if (attrs != null)
{
attrs.setNamedItemNS(node);
}
}
else
{
if (nextSibling != null)
{
parent.insertBefore(node, nextSibling);
}
else
{
parent.appendChild(node);
}
}
}
}
else
{
String value = Expr._string(context, ret);
if (value != null && value.length() > 0)
{
Text textNode = doc.createTextNode(value);
if (nextSibling != null)
{
parent.insertBefore(textNode, nextSibling);
}
else
{
parent.appendChild(textNode);
}
}
}
// copy-of doesn't process children
if (next != null)
{
next.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
}
public boolean references(QName var)
{
if (select != null && select.references(var))
{
return true;
}
return super.references(var);
}
public String toString()
{
StringBuffer buf = new StringBuffer(getClass().getName());
buf.append('[');
buf.append("select=");
buf.append(select);
buf.append(']');
return buf.toString();
}
}
@@ -0,0 +1,104 @@
/* CurrentFunction.java --
Copyright (C) 2004 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 java.util.Collections;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.xpath.XPathFunction;
import javax.xml.xpath.XPathFunctionException;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
import gnu.xml.xpath.Function;
/**
* The XSLT <code>current()</code>function.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class CurrentFunction
extends Expr
implements Function, XPathFunction
{
final Stylesheet stylesheet;
CurrentFunction(Stylesheet stylesheet)
{
this.stylesheet = stylesheet;
}
public Object evaluate(List args)
throws XPathFunctionException
{
// We can't do anything useful here.
// So much for the JAXP API...
return Collections.EMPTY_SET;
}
public void setArguments(List args)
{
}
public Object evaluate(Node context, int pos, int len)
{
return Collections.singleton(stylesheet.current);
}
public Expr clone(Object context)
{
Stylesheet s = stylesheet;
if (context instanceof Stylesheet)
{
s = (Stylesheet) context;
}
return new CurrentFunction(s);
}
public boolean references(QName var)
{
return false;
}
public String toString()
{
return "current()";
}
}
@@ -0,0 +1,84 @@
/* DOMSourceLocator.java --
Copyright (C) 2004 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 javax.xml.transform.dom.DOMLocator;
import org.w3c.dom.Node;
/**
* Simple DOMLocator implementation.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
class DOMSourceLocator
implements DOMLocator
{
final Node node;
DOMSourceLocator(Node node)
{
this.node = node;
}
public Node getOriginatingNode()
{
return node;
}
public String getPublicId()
{
return null;
}
public String getSystemId()
{
return null;
}
public int getLineNumber()
{
return -1;
}
public int getColumnNumber()
{
return -1;
}
}
@@ -0,0 +1,256 @@
/* DocumentFunction.java --
Copyright (C) 2004 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 java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;
import javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.xpath.XPathFunction;
import javax.xml.xpath.XPathFunctionException;
import org.w3c.dom.Node;
import gnu.xml.xpath.Constant;
import gnu.xml.xpath.Expr;
import gnu.xml.xpath.Function;
import gnu.xml.xpath.IdFunction;
/**
* The XSLT <code>document()</code>function.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class DocumentFunction
extends Expr
implements Function, XPathFunction
{
final Stylesheet stylesheet;
final Node base;
List args;
List values;
DocumentFunction(Stylesheet stylesheet, Node base)
{
this.stylesheet = stylesheet;
this.base = base;
}
public Object evaluate(List args)
throws XPathFunctionException
{
values = args;
return evaluate(null, 1, 1);
}
public void setArguments(List args)
{
this.args = args;
}
public Object evaluate(Node context, int pos, int len)
{
int arity = args.size();
if (values == null)
{
values = new ArrayList(arity);
for (int i = 0; i < arity; i++)
{
Expr arg = (Expr) args.get(i);
values.add(arg.evaluate(context, pos, len));
}
}
Object ret;
switch (arity)
{
case 1:
Object arg = values.get(0);
if (arg instanceof Collection)
{
Collection ns = (Collection) arg;
Collection acc = new TreeSet();
for (Iterator i = ns.iterator(); i.hasNext(); )
{
Node node = (Node) i.next();
String s = Expr.stringValue(node);
acc.addAll(document(s, node.getBaseURI()));
}
ret = acc;
}
else
{
String s = Expr._string(context, arg);
ret = document(s, base.getBaseURI());
}
break;
case 2:
Object arg1 = values.get(0);
Object arg2 = values.get(1);
if (!(arg2 instanceof Collection))
{
throw new RuntimeException("second argument is not a node-set");
}
Collection arg2ns = (Collection) arg2;
String base2 = arg2ns.isEmpty() ? null :
((Node) arg2ns.iterator().next()).getBaseURI();
if (arg1 instanceof Collection)
{
Collection arg1ns = (Collection) arg1;
Collection acc = new TreeSet();
for (Iterator i = arg1ns.iterator(); i.hasNext(); )
{
Node node = (Node) i.next();
String s = Expr.stringValue(node);
acc.addAll(document(s, base2));
}
ret = acc;
}
else
{
String s = Expr._string(context, arg1);
ret = document(s, base2);
}
break;
default:
throw new RuntimeException("invalid arity");
}
values = null;
return ret;
}
/**
* The XSL <code>document</code> function.
* @see XSLT 12.1
* @param uri the URI from which to retrieve nodes
* @param base the base URI for relative URIs
*/
Collection document(String uri, String base)
{
if ("".equals(uri) || uri == null)
{
uri = this.base.getBaseURI();
}
// Get fragment
Expr fragment = null;
int hi = uri.indexOf('#');
if (hi != -1)
{
String f = uri.substring(hi + 1);
uri = uri.substring(0, hi);
// TODO handle xpointer() here
// this only handles IDs
fragment = new IdFunction(new Constant(f));
}
// Get document source
try
{
DOMSource source;
XSLURIResolver resolver = stylesheet.factory.resolver;
synchronized (resolver)
{
if (stylesheet.transformer != null)
{
resolver.setUserResolver(stylesheet.transformer.uriResolver);
resolver.setUserListener(stylesheet.transformer.errorListener);
}
source = resolver.resolveDOM(null, base, uri);
}
Node node = source.getNode();
if (fragment == null)
{
return Collections.singleton(node);
}
else
{
Object ret = fragment.evaluate(node, 1, 1);
if (!(ret instanceof Collection))
{
// XXX Report error?
return Collections.EMPTY_SET;
}
return (Collection) ret;
}
}
catch (TransformerException e)
{
String msg = "can't open " + uri;
if (base != null)
{
msg += " with base " + base;
}
throw new RuntimeException(msg);
}
}
public Expr clone(Object context)
{
Stylesheet s = stylesheet;
if (context instanceof Stylesheet)
{
s = (Stylesheet) context;
}
DocumentFunction f = new DocumentFunction(s, base);
int len = args.size();
List args2 = new ArrayList(len);
for (int i = 0; i < len; i++)
{
args2.add(((Expr) args.get(i)).clone(context));
}
f.setArguments(args2);
return f;
}
public boolean references(QName var)
{
for (Iterator i = args.iterator(); i.hasNext(); )
{
if (((Expr) i.next()).references(var))
{
return true;
}
}
return false;
}
}
@@ -0,0 +1,183 @@
/* ElementAvailableFunction.java --
Copyright (C) 2004 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 java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;
import javax.xml.namespace.QName;
import javax.xml.namespace.NamespaceContext;
import javax.xml.xpath.XPathFunction;
import javax.xml.xpath.XPathFunctionException;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
import gnu.xml.xpath.Function;
/**
* The XSLT <code>element-available</code> function.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
class ElementAvailableFunction
extends Expr
implements Function, XPathFunction
{
static final Collection elements;
static
{
TreeSet acc = new TreeSet();
acc.add("stylesheet");
acc.add("template");
acc.add("param");
acc.add("variable");
acc.add("include");
acc.add("import");
acc.add("output");
acc.add("preserve-space");
acc.add("strip-space");
acc.add("key");
acc.add("decimal-format");
acc.add("namespace-alias");
acc.add("attribute-set");
acc.add("apply-templates");
acc.add("call-template");
acc.add("value-of");
acc.add("for-each");
acc.add("if");
acc.add("choose");
acc.add("when");
acc.add("otherwise");
acc.add("element");
acc.add("attribute");
acc.add("text");
acc.add("copy");
acc.add("processing-instruction");
acc.add("comment");
acc.add("number");
acc.add("copy-of");
acc.add("message");
acc.add("sort");
acc.add("with-param");
acc.add("fallback");
acc.add("apply-imports");
elements = Collections.unmodifiableSet(acc);
}
final NamespaceContext nsctx;
List args;
ElementAvailableFunction(NamespaceContext nsctx)
{
this.nsctx = nsctx;
}
public Object evaluate(List args)
throws XPathFunctionException
{
// Useless...
return Collections.EMPTY_SET;
}
public void setArguments(List args)
{
this.args = args;
}
public Object evaluate(Node context, int pos, int len)
{
Expr arg = (Expr) args.get(0);
Object val = arg.evaluate(context, pos, len);
String name = _string(context, val);
String prefix, localName, uri;
int ci = name.indexOf(':');
if (ci == -1)
{
prefix = null;
localName = name;
}
else
{
prefix = name.substring(0, ci);
localName = name.substring(ci + 1);
}
uri = nsctx.getNamespaceURI(prefix);
if (Stylesheet.XSL_NS.equals(uri))
{
return elements.contains(localName) ?
Boolean.TRUE : Boolean.FALSE;
// TODO extension elements
}
return Boolean.FALSE;
}
public Expr clone(Object context)
{
NamespaceContext n = nsctx;
if (context instanceof NamespaceContext)
{
n = (NamespaceContext) context;
}
ElementAvailableFunction f = new ElementAvailableFunction(n);
int len = args.size();
List args2 = new ArrayList(len);
for (int i = 0; i < len; i++)
{
args2.add(((Expr) args.get(i)).clone(context));
}
f.setArguments(args2);
return f;
}
public boolean references(QName var)
{
for (Iterator i = args.iterator(); i.hasNext(); )
{
if (((Expr) i.next()).references(var))
{
return true;
}
}
return false;
}
}
@@ -0,0 +1,296 @@
/* ElementNode.java --
Copyright (C) 2004 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 java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.StringTokenizer;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
/**
* A template node representing an XSL <code>element</code> instruction.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class ElementNode
extends TemplateNode
{
final TemplateNode name;
final TemplateNode namespace;
final String uas;
final Node source;
final Collection elementExcludeResultPrefixes;
ElementNode(TemplateNode name,
TemplateNode namespace, String uas, Node source)
{
this.name = name;
this.namespace = namespace;
this.uas = uas;
this.source = source;
NamedNodeMap attrs = source.getAttributes();
Node attr = attrs.getNamedItemNS(Stylesheet.XSL_NS,
"exclude-result-prefixes");
if (attr != null)
{
elementExcludeResultPrefixes = new HashSet();
StringTokenizer st = new StringTokenizer(attr.getNodeValue());
while (st.hasMoreTokens())
{
elementExcludeResultPrefixes.add(st.nextToken());
}
}
else
{
elementExcludeResultPrefixes = Collections.EMPTY_SET;
}
}
TemplateNode clone(Stylesheet stylesheet)
{
TemplateNode ret = new ElementNode(name.clone(stylesheet),
(namespace == null) ? null :
namespace.clone(stylesheet),
uas, source);
if (children != null)
{
ret.children = children.clone(stylesheet);
}
if (next != null)
{
ret.next = next.clone(stylesheet);
}
return ret;
}
void doApply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
Document doc = (parent instanceof Document) ? (Document) parent :
parent.getOwnerDocument();
// Create a document fragment to hold the name
DocumentFragment fragment = doc.createDocumentFragment();
// Apply name to the fragment
name.apply(stylesheet, mode,
context, pos, len,
fragment, null);
// Use XPath string-value of fragment
String nameValue = Expr.stringValue(fragment);
String namespaceValue = null;
if (namespace != null)
{
// Create a document fragment to hold the namespace
fragment = doc.createDocumentFragment();
// Apply namespace to the fragment
namespace.apply(stylesheet, mode,
context, pos, len,
fragment, null);
// Use XPath string-value of fragment
namespaceValue = Expr.stringValue(fragment);
if (namespaceValue.length() == 0)
{
namespaceValue = null;
}
}
String prefix = getPrefix(nameValue);
if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix))
{
int ci = nameValue.indexOf(':');
nameValue = nameValue.substring(ci + 1);
}
else
{
// Namespace aliasing
if (prefix == null)
{
prefix = "#default";
}
String resultPrefix =
(String) stylesheet.namespaceAliases.get(prefix);
if (resultPrefix != null)
{
if ("#default".equals(resultPrefix))
{
resultPrefix = null;
}
namespaceValue = source.lookupNamespaceURI(resultPrefix);
}
if (prefix == "#default")
{
prefix = null;
}
// Look up ordinary namespace for this prefix
if (namespaceValue == null)
{
if (XMLConstants.XML_NS_PREFIX.equals(prefix))
{
namespaceValue = XMLConstants.XML_NS_URI;
}
else
{
// Resolve namespace for this prefix
namespaceValue = source.lookupNamespaceURI(prefix);
}
}
/*if (prefix == null)
{
// Resolve prefix for this namespace
prefix = parent.lookupPrefix(namespaceValue);
if (prefix != null)
{
nameValue = prefix + ":" + nameValue;
}
}*/
}
// Create element
Element element = (namespaceValue != null) ?
doc.createElementNS(namespaceValue, nameValue) :
doc.createElement(nameValue);
if (nextSibling != null)
{
parent.insertBefore(element, nextSibling);
}
else
{
parent.appendChild(element);
}
stylesheet.addNamespaceNodes(source, element, doc,
elementExcludeResultPrefixes);
if (uas != null)
{
StringTokenizer st = new StringTokenizer(uas, " ");
while (st.hasMoreTokens())
{
addAttributeSet(stylesheet, mode, context, pos, len,
element, null, st.nextToken());
}
}
if (children != null)
{
children.apply(stylesheet, mode,
context, pos, len,
element, null);
}
if (next != null)
{
next.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
}
final String getPrefix(String name)
{
int ci = name.indexOf(':');
return (ci == -1) ? null : name.substring(0, ci);
}
void addAttributeSet(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling, String attributeSet)
throws TransformerException
{
for (Iterator i = stylesheet.attributeSets.iterator(); i.hasNext(); )
{
AttributeSet as = (AttributeSet) i.next();
if (!as.name.equals(attributeSet))
{
continue;
}
if (as.uas != null)
{
StringTokenizer st = new StringTokenizer(as.uas, " ");
while (st.hasMoreTokens())
{
addAttributeSet(stylesheet, mode, context, pos, len,
parent, nextSibling, st.nextToken());
}
}
if (as.children != null)
{
as.children.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
}
}
public boolean references(QName var)
{
if (name != null && name.references(var))
{
return true;
}
if (namespace != null && namespace.references(var))
{
return true;
}
return super.references(var);
}
public String toString()
{
StringBuffer buf = new StringBuffer(getClass().getName());
buf.append('[');
buf.append("name=");
buf.append(name);
if (uas != null)
{
buf.append(",uas=");
buf.append(uas);
}
buf.append(']');
return buf.toString();
}
}
@@ -0,0 +1,101 @@
/* ErrorListenerErrorHandler.java --
Copyright (C) 2004 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 javax.xml.transform.ErrorListener;
import javax.xml.transform.TransformerException;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* An ErrorHandler that wraps an ErrorListener.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
class ErrorListenerErrorHandler
implements ErrorHandler
{
final ErrorListener listener;
ErrorListenerErrorHandler(ErrorListener listener)
{
this.listener = listener;
}
public void warning(SAXParseException e)
throws SAXException
{
try
{
listener.warning(new TransformerException(e));
}
catch (TransformerException e2)
{
throw new SAXException(e2);
}
}
public void error(SAXParseException e)
throws SAXException
{
try
{
listener.error(new TransformerException(e));
}
catch (TransformerException e2)
{
throw new SAXException(e2);
}
}
public void fatalError(SAXParseException e)
throws SAXException
{
try
{
listener.fatalError(new TransformerException(e));
}
catch (TransformerException e2)
{
throw new SAXException(e2);
}
}
}
@@ -0,0 +1,171 @@
/* ForEachNode.java --
Copyright (C) 2004 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 java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
/**
* A template node representing an XSLT <code>for-each</code> instruction.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class ForEachNode
extends TemplateNode
{
final Expr select;
final List sortKeys;
ForEachNode(Expr select, List sortKeys)
{
this.select = select;
this.sortKeys = sortKeys;
}
TemplateNode clone(Stylesheet stylesheet)
{
int len = sortKeys.size();
List sortKeys2 = new ArrayList(len);
for (int i = 0; i < len; i++)
{
sortKeys2.add(((Key) sortKeys.get(i)).clone(stylesheet));
}
TemplateNode ret = new ForEachNode(select.clone(stylesheet),
sortKeys2);
if (children != null)
{
ret.children = children.clone(stylesheet);
}
if (next != null)
{
ret.next = next.clone(stylesheet);
}
return ret;
}
void doApply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
if (children != null)
{
// Set current template to null
Template saved = stylesheet.currentTemplate;
stylesheet.currentTemplate = null;
Object ret = select.evaluate(context, pos, len);
//System.err.println(toString() + ": " + context+" -> "+ret);
if (ret instanceof Collection)
{
Collection ns = (Collection) ret;
List list = new ArrayList(ns);
if (sortKeys != null)
{
for (Iterator i = sortKeys.iterator(); i.hasNext(); )
{
SortKey sortKey = (SortKey) i.next();
sortKey.init(stylesheet, mode, context, pos, len, parent,
nextSibling);
}
Collections.sort(list, new XSLComparator(sortKeys));
}
else
{
Collections.sort(list, documentOrderComparator);
}
// Perform children for each node
int l = list.size();
int p = 1;
for (Iterator i = list.iterator(); i.hasNext(); )
{
Node node = (Node) i.next();
stylesheet.current = node;
children.apply(stylesheet, mode,
node, p++, l,
parent, nextSibling);
}
}
// Restore current template
stylesheet.currentTemplate = saved;
}
if (next != null)
{
next.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
}
public boolean references(QName var)
{
if (select != null && select.references(var))
{
return true;
}
if (sortKeys != null)
{
for (Iterator i = sortKeys.iterator(); i.hasNext(); )
{
if (((SortKey) i.next()).references(var))
{
return true;
}
}
}
return super.references(var);
}
public String toString()
{
StringBuffer buf = new StringBuffer(getClass().getName());
buf.append('[');
buf.append("select=");
buf.append(select);
buf.append(']');
return buf.toString();
}
}
@@ -0,0 +1,146 @@
/* FormatNumberFunction.java --
Copyright (C) 2004 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 java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.xpath.XPathFunction;
import javax.xml.xpath.XPathFunctionException;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
import gnu.xml.xpath.Function;
/**
* The XSLT <code>format-number()</code>function.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class FormatNumberFunction
extends Expr
implements XPathFunction, Function
{
final Stylesheet stylesheet;
List args;
FormatNumberFunction(Stylesheet stylesheet)
{
this.stylesheet = stylesheet;
}
public Object evaluate(List args)
throws XPathFunctionException
{
// Useless...
return Collections.EMPTY_SET;
}
public void setArguments(List args)
{
this.args = args;
}
public Object evaluate(Node context, int pos, int len)
{
int arity = args.size();
List values = new ArrayList(arity);
for (int i = 0; i < arity; i++)
{
Expr arg = (Expr) args.get(i);
values.add(arg.evaluate(context, pos, len));
}
double number = _number(context, values.get(0));
String pattern = _string(context, values.get(1));
// Currency symbol &#x00a4; is not supposed to be present
if (pattern.indexOf('\u00a4') != -1)
{
// Replace with $ (Xalan does this)
pattern = pattern.replace('\u00a4', '$');
}
String dfName = null;
if (arity > 2)
{
dfName = _string(context, values.get(2));
// otherwise the default decimal-format will be used
}
DecimalFormat df = (DecimalFormat) stylesheet.decimalFormats.get(dfName);
if (df == null)
{
throw new IllegalArgumentException("No such decimal-format: " +
dfName);
}
df.applyLocalizedPattern(pattern);
return df.format(number);
}
public Expr clone(Object context)
{
Stylesheet s = stylesheet;
if (context instanceof Stylesheet)
{
s = (Stylesheet) context;
}
FormatNumberFunction f = new FormatNumberFunction(s);
int len = args.size();
List args2 = new ArrayList(len);
for (int i = 0; i < len; i++)
{
args2.add(((Expr) args.get(i)).clone(context));
}
f.setArguments(args2);
return f;
}
public boolean references(QName var)
{
for (Iterator i = args.iterator(); i.hasNext(); )
{
if (((Expr) i.next()).references(var))
{
return true;
}
}
return false;
}
}
@@ -0,0 +1,189 @@
/* FunctionAvailableFunction.java --
Copyright (C) 2004 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 java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.xpath.XPathFunction;
import javax.xml.xpath.XPathFunctionException;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
import gnu.xml.xpath.Function;
/**
* The XSLT <code>function-available</code> function.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
class FunctionAvailableFunction
extends Expr
implements Function, XPathFunction
{
static final Collection xsltFunctions;
static final Collection xpathFunctions;
static
{
TreeSet acc = new TreeSet();
acc.add("document");
acc.add("key");
acc.add("format-number");
acc.add("current");
acc.add("unparsed-entity-uri");
acc.add("generate-id");
acc.add("system-property");
acc.add("element-available");
acc.add("function-available");
xsltFunctions = Collections.unmodifiableSet(acc);
acc = new TreeSet();
acc.add("boolean");
acc.add("ceiling");
acc.add("concat");
acc.add("contains");
acc.add("count");
acc.add("false");
acc.add("floor");
acc.add("id");
acc.add("lang");
acc.add("last");
acc.add("local-name");
acc.add("name");
acc.add("namespace-uri");
acc.add("normalize-space");
acc.add("not");
acc.add("number");
acc.add("position");
acc.add("round");
acc.add("starts-with");
acc.add("string");
acc.add("string-length");
acc.add("substring-after");
acc.add("substring-before");
acc.add("substring");
acc.add("sum");
acc.add("translate");
acc.add("true");
xpathFunctions = Collections.unmodifiableSet(acc);
}
final NamespaceContext nsctx;
List args;
FunctionAvailableFunction(NamespaceContext nsctx)
{
this.nsctx = nsctx;
}
public Object evaluate(List args)
throws XPathFunctionException
{
// Useless...
return Collections.EMPTY_SET;
}
public void setArguments(List args)
{
this.args = args;
}
public Object evaluate(Node context, int pos, int len)
{
Expr arg = (Expr) args.get(0);
Object val = arg.evaluate(context, pos, len);
String name = _string(context, val);
String prefix, localName, uri;
int ci = name.indexOf(':');
if (ci == -1)
{
prefix = null;
localName = name;
}
else
{
prefix = name.substring(0, ci);
localName = name.substring(ci + 1);
}
uri = nsctx.getNamespaceURI(prefix);
if (uri == null)
{
return xsltFunctions.contains(localName) ||
xpathFunctions.contains(localName) ?
Boolean.TRUE : Boolean.FALSE;
// TODO extension functions
}
return Boolean.FALSE;
}
public Expr clone(Object context)
{
NamespaceContext n = nsctx;
if (context instanceof NamespaceContext)
{
n = (NamespaceContext) context;
}
FunctionAvailableFunction f = new FunctionAvailableFunction(n);
int len = args.size();
List args2 = new ArrayList(len);
for (int i = 0; i < len; i++)
{
args2.add(((Expr) args.get(i)).clone(context));
}
f.setArguments(args2);
return f;
}
public boolean references(QName var)
{
for (Iterator i = args.iterator(); i.hasNext(); )
{
if (((Expr) i.next()).references(var))
{
return true;
}
}
return false;
}
}
@@ -0,0 +1,140 @@
/* GenerateIdFunction.java --
Copyright (C) 2004 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 java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.xpath.XPathFunction;
import javax.xml.xpath.XPathFunctionException;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
import gnu.xml.xpath.Function;
/**
* The XSLT <code>generate-id()</code>function.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class GenerateIdFunction
extends Expr
implements XPathFunction, Function
{
List args;
public Object evaluate(List args)
throws XPathFunctionException
{
// Useless...
return Collections.EMPTY_SET;
}
public void setArguments(List args)
{
this.args = args;
}
public Object evaluate(Node context, int pos, int len)
{
int arity = args.size();
List values = new ArrayList(arity);
for (int i = 0; i < arity; i++)
{
Expr arg = (Expr) args.get(i);
values.add(arg.evaluate(context, pos, len));
}
Node node;
Collection ns = (arity == 0) ? Collections.EMPTY_SET :
(Collection) values.get(0);
if (ns.isEmpty())
{
node = context;
}
else
{
List list = new ArrayList(ns);
Collections.sort(list, documentOrderComparator);
node = (Node) list.get(0);
}
String name = node.getNodeName();
int index = 0, depth = 0;
for (Node ctx = node.getPreviousSibling(); ctx != null;
ctx = ctx.getPreviousSibling())
{
index++;
}
for (Node ctx = node.getParentNode(); ctx != null;
ctx = ctx.getParentNode())
{
depth++;
}
return name + "-" + index + "-" + depth;
}
public Expr clone(Object context)
{
GenerateIdFunction f = new GenerateIdFunction();
int len = args.size();
List args2 = new ArrayList(len);
for (int i = 0; i < len; i++)
{
args2.add(((Expr) args.get(i)).clone(context));
}
f.setArguments(args2);
return f;
}
public boolean references(QName var)
{
for (Iterator i = args.iterator(); i.hasNext(); )
{
if (((Expr) i.next()).references(var))
{
return true;
}
}
return false;
}
}
@@ -0,0 +1,120 @@
/* IfNode.java --
Copyright (C) 2004 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 javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
/**
* A template node representing an XSL <code>if</code> instruction.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class IfNode
extends TemplateNode
{
final Expr test;
IfNode(Expr test)
{
this.test = test;
}
TemplateNode clone(Stylesheet stylesheet)
{
TemplateNode ret = new IfNode(test.clone(stylesheet));
if (children != null)
{
ret.children = children.clone(stylesheet);
}
if (next != null)
{
ret.next = next.clone(stylesheet);
}
return ret;
}
void doApply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
Object ret = test.evaluate(context, pos, len);
boolean success = (ret instanceof Boolean) ?
((Boolean) ret).booleanValue() :
Expr._boolean(context, ret);
if (success)
{
if (children != null)
{
children.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
}
if (next != null)
{
next.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
}
public boolean references(QName var)
{
if (test != null && test.references(var))
{
return true;
}
return super.references(var);
}
public String toString()
{
StringBuffer buf = new StringBuffer(getClass().getName());
buf.append('[');
buf.append("test=");
buf.append(test);
buf.append(']');
return buf.toString();
}
}
@@ -0,0 +1,71 @@
/* Key.java --
Copyright (C) 2004 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 javax.xml.namespace.QName;
import gnu.xml.xpath.Expr;
import gnu.xml.xpath.Pattern;
/**
* An XSL key.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
class Key
{
final QName name;
final Pattern match;
final Expr use;
Key(QName name, Pattern match, Expr use)
{
this.name = name;
this.match = match;
this.use = use;
}
Key clone(Stylesheet stylesheet)
{
return new Key(name,
(Pattern) match.clone(stylesheet),
use.clone(stylesheet));
}
}
@@ -0,0 +1,228 @@
/* KeyFunction.java --
Copyright (C) 2004 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 java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.xpath.XPathFunction;
import javax.xml.xpath.XPathFunctionException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
import gnu.xml.xpath.Function;
import gnu.xml.xpath.Pattern;
/**
* The XSLT <code>key()</code>function.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class KeyFunction
extends Pattern
implements XPathFunction, Function
{
final Stylesheet stylesheet;
List args;
KeyFunction(Stylesheet stylesheet)
{
this.stylesheet = stylesheet;
}
public Object evaluate(List args)
throws XPathFunctionException
{
// Useless...
return Collections.EMPTY_SET;
}
public void setArguments(List args)
{
this.args = args;
}
public boolean matches(Node context)
{
Object ret = evaluate(context, 1, 1);
return !((Collection) ret).isEmpty();
}
public Object evaluate(Node context, int pos, int len)
{
// Evaluate arguments
int arity = args.size();
List values = new ArrayList(arity);
for (int i = 0; i < arity; i++)
{
Expr arg = (Expr) args.get(i);
values.add(arg.evaluate(context, pos, len));
}
// Get key name
QName keyName = QName.valueOf(_string(context, values.get(0)));
// Expand qualified name
String uri = keyName.getNamespaceURI();
String prefix = keyName.getPrefix();
if ((uri == null || uri.length() == 0) &&
(prefix != null && prefix.length() > 0))
{
uri = stylesheet.getNamespaceURI(prefix);
if (uri != null && uri.length() > 0)
{
String localName = keyName.getLocalPart();
keyName = new QName(uri, localName, prefix);
}
}
// Compute matching key set
Collection keySet = new LinkedList();
for (Iterator i = stylesheet.keys.iterator(); i.hasNext(); )
{
Key key = (Key) i.next();
if (key.name.equals(keyName))
{
keySet.add(key);
}
}
// Get target
Object target = values.get(1);
Collection acc = new LinkedHashSet();
Document doc = (context instanceof Document) ? (Document) context :
context.getOwnerDocument();
if (target instanceof Collection)
{
for (Iterator i = ((Collection) target).iterator(); i.hasNext(); )
{
String val = Expr.stringValue((Node) i.next());
addKeyNodes(doc, keySet, val, acc);
}
}
else
{
String val = Expr._string(context, target);
addKeyNodes(doc, keySet, val, acc);
}
List ret = new ArrayList(acc);
Collections.sort(ret, documentOrderComparator);
return ret;
}
final void addKeyNodes(Node node, Collection keySet,
String value, Collection acc)
{
addKeyNodeIfMatch(node, keySet, value, acc);
// Apply children
for (Node ctx = node.getFirstChild(); ctx != null;
ctx = ctx.getNextSibling())
{
addKeyNodes(ctx, keySet, value, acc);
}
}
final void addKeyNodeIfMatch(Node node, Collection keySet,
String value, Collection acc)
{
for (Iterator i = keySet.iterator(); i.hasNext(); )
{
Key key = (Key) i.next();
if (key.match.matches(node))
{
Object eval = key.use.evaluate(node, 1, 1);
if (eval instanceof Collection)
{
for (Iterator j = ((Collection) eval).iterator();
j.hasNext(); )
{
String keyValue = Expr.stringValue((Node) j.next());
if (value.equals(keyValue))
{
acc.add(node);
return;
}
}
}
else
{
String keyValue = Expr._string(node, eval);
if (value.equals(keyValue))
{
acc.add(node);
return;
}
}
}
}
}
public Expr clone(Object context)
{
Stylesheet s = stylesheet;
if (context instanceof Stylesheet)
{
s = (Stylesheet) context;
}
KeyFunction f = new KeyFunction(s);
int len = args.size();
List args2 = new ArrayList(len);
for (int i = 0; i < len; i++)
{
args2.add(((Expr) args.get(i)).clone(context));
}
f.setArguments(args2);
return f;
}
public boolean references(QName var)
{
for (Iterator i = args.iterator(); i.hasNext(); )
{
if (((Expr) i.next()).references(var))
{
return true;
}
}
return false;
}
}
@@ -0,0 +1,231 @@
/* LiteralNode.java --
Copyright (C) 2004 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 java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.StringTokenizer;
import javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
/**
* A template node that copies a DOM node in the template to the result
* tree.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class LiteralNode
extends TemplateNode
{
/**
* The source node in the XSL template.
*/
final Node source;
final Collection elementExcludeResultPrefixes;
LiteralNode(Node source)
{
this.source = source;
if (source.getNodeType() == Node.ELEMENT_NODE)
{
NamedNodeMap attrs = source.getAttributes();
Node attr = attrs.getNamedItemNS(Stylesheet.XSL_NS,
"exclude-result-prefixes");
if (attr != null)
{
elementExcludeResultPrefixes = new HashSet();
StringTokenizer st = new StringTokenizer(attr.getNodeValue());
while (st.hasMoreTokens())
{
elementExcludeResultPrefixes.add(st.nextToken());
}
}
else
{
elementExcludeResultPrefixes = Collections.EMPTY_SET;
}
}
else
{
elementExcludeResultPrefixes = null;
}
}
TemplateNode clone(Stylesheet stylesheet)
{
TemplateNode ret = new LiteralNode(source);
if (children != null)
{
ret.children = children.clone(stylesheet);
}
if (next != null)
{
ret.next = next.clone(stylesheet);
}
return ret;
}
void doApply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
Node result = null;
Document doc = (parent instanceof Document) ? (Document) parent :
parent.getOwnerDocument();
short nodeType = source.getNodeType();
if (nodeType == Node.ATTRIBUTE_NODE &&
parent.getFirstChild() != null)
{
// Ignore attributes added after child elements
}
else
{
// Namespace aliasing
if (nodeType == Node.ELEMENT_NODE)
{
String prefix = source.getPrefix();
if (prefix == null)
{
prefix = "#default";
}
String resultPrefix =
(String) stylesheet.namespaceAliases.get(prefix);
if (resultPrefix != null)
{
if ("#default".equals(resultPrefix))
{
resultPrefix = null;
}
String uri = source.lookupNamespaceURI(resultPrefix);
String name = source.getNodeName();
// Create a new element node in the result document
result = doc.createElementNS(uri, name);
// copy attributes
NamedNodeMap srcAttrs = source.getAttributes();
NamedNodeMap dstAttrs = result.getAttributes();
int l = srcAttrs.getLength();
for (int i = 0; i < l; i++)
{
Node attr = srcAttrs.item(i);
if (!Stylesheet.XSL_NS.equals(attr.getNamespaceURI()))
{
attr = attr.cloneNode(true);
attr = doc.adoptNode(attr);
dstAttrs.setNamedItemNS(attr);
}
}
}
}
if (result == null)
{
// Create result node
result = source.cloneNode(false);
// Remove any XSL attributes
NamedNodeMap attrs = result.getAttributes();
if (attrs != null)
{
int l = attrs.getLength();
for (int i = 0; i < l; i++)
{
Node attr = attrs.item(i);
if (Stylesheet.XSL_NS.equals(attr.getNamespaceURI()))
{
attrs.removeNamedItem(attr.getNodeName());
i--;
l--;
}
}
}
Node result2 = doc.adoptNode(result);
if (result2 == null)
{
String msg = "Error adopting node to result tree: " +
result + " (" + result.getClass().getName() + ")";
DOMSourceLocator l = new DOMSourceLocator(context);
throw new TransformerException(msg, l);
}
result = result2;
}
if (nextSibling != null)
{
parent.insertBefore(result, nextSibling);
}
else
{
parent.appendChild(result);
}
if (nodeType == Node.ELEMENT_NODE)
{
stylesheet.addNamespaceNodes(source, result, doc,
elementExcludeResultPrefixes);
}
// children
if (children != null)
{
children.apply(stylesheet, mode,
context, pos, len,
result, null);
}
}
// next sibling
if (next != null)
{
next.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
}
public String toString()
{
StringBuffer buf = new StringBuffer(getClass().getName());
buf.append('[');
buf.append("source=");
buf.append(source);
buf.append(']');
return buf.toString();
}
}
@@ -0,0 +1,101 @@
/* MessageNode.java --
Copyright (C) 2004 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 javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
/**
* An XSL <code>message</code> instruction.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class MessageNode
extends TemplateNode
{
final boolean terminate;
MessageNode(boolean terminate)
{
this.terminate = terminate;
}
TemplateNode clone(Stylesheet stylesheet)
{
TemplateNode ret = new MessageNode(terminate);
if (children != null)
{
ret.children = children.clone(stylesheet);
}
if (next != null)
{
ret.next = next.clone(stylesheet);
}
return ret;
}
void doApply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
if (children != null)
{
Document doc = (parent instanceof Document) ? (Document) parent :
parent.getOwnerDocument();
DocumentFragment fragment = doc.createDocumentFragment();
children.apply(stylesheet, mode, context, pos, len, fragment, null);
String message = Expr.stringValue(fragment);
System.err.println(message);
if (terminate)
{
stylesheet.terminated = true;
}
}
if (next != null && !terminate)
{
next.apply(stylesheet, mode, context, pos, len, parent, nextSibling);
}
}
}
@@ -0,0 +1,269 @@
/* NodeNumberNode.java --
Copyright (C) 2004 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 java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
import gnu.xml.xpath.Pattern;
import gnu.xml.xpath.Selector;
import gnu.xml.xpath.UnionExpr;
/**
* A template node representing the XSL <code>number</code> instruction
* with no <code>value</code> expression, i.e. the value is computed from
* the document position of the context node.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class NodeNumberNode
extends AbstractNumberNode
{
static final int SINGLE = 0;
static final int MULTIPLE = 1;
static final int ANY = 2;
final int level;
final Pattern count;
final Pattern from;
NodeNumberNode(int level, Pattern count, Pattern from,
TemplateNode format, String lang,
int letterValue, String groupingSeparator, int groupingSize)
{
super(format, lang, letterValue, groupingSeparator, groupingSize);
this.level = level;
this.count = count;
this.from = from;
}
TemplateNode clone(Stylesheet stylesheet)
{
TemplateNode ret = new NodeNumberNode(level,
(count == null) ? null :
(Pattern) count.clone(stylesheet),
(from == null) ? from :
(Pattern) from.clone(stylesheet),
format, lang, letterValue,
groupingSeparator, groupingSize);
if (children != null)
{
ret.children = children.clone(stylesheet);
}
if (next != null)
{
ret.next = next.clone(stylesheet);
}
return ret;
}
int[] compute(Stylesheet stylesheet, Node context, int pos, int len)
throws TransformerException
{
/*if (from != null)
{
Object ret = from.evaluate(context, pos, len);
if (ret instanceof Collection)
{
Collection ns = (Collection) ret;
if (ns.size() > 0)
{
List list = new ArrayList(ns);
Collections.sort(list, documentOrderComparator);
context = (Node) list.get(0);
}
else
{
return new int[0];
}
}
else
{
return new int[0];
}
}*/
Node current = context;
switch (level)
{
case SINGLE:
if (from == null)
{
while (context != null && !countMatches(current, context))
{
context = context.getParentNode();
}
}
else
{
while (context != null && !countMatches(current, context) &&
!fromMatches(context))
{
context = context.getParentNode();
}
}
return (context == null) ? new int[0] :
new int[] { (context == current) ? pos : getIndex(current, context) };
case MULTIPLE:
List ancestors = new ArrayList();
while (context != null)
{
if (countMatches(current, context))
{
if (from == null || fromMatches(context))
{
ancestors.add(context);
}
}
context = context.getParentNode();
}
Collections.sort(ancestors, documentOrderComparator);
int[] ret = new int[ancestors.size()];
for (int i = 0; i < ret.length; i++)
{
ret[i] = getIndex(current, (Node) ancestors.get(i));
}
return ret;
case ANY:
Expr preceding = new Selector(Selector.PRECEDING,
Collections.EMPTY_LIST);
Expr ancestorOrSelf = new Selector(Selector.ANCESTOR_OR_SELF,
Collections.EMPTY_LIST);
Expr any = new UnionExpr(preceding, ancestorOrSelf);
Object eval = any.evaluate(context, pos, len);
if (eval instanceof Collection)
{
Collection ns = (Collection) eval;
List candidates = new ArrayList();
for (Iterator i = ns.iterator(); i.hasNext(); )
{
Node candidate = (Node) i.next();
if (countMatches(current, candidate))
{
candidates.add(candidate);
if (from != null && from.matches(candidate))
{
break;
}
}
}
return new int[] { candidates.size() };
}
return new int[0];
default:
throw new TransformerException("invalid level");
}
}
boolean countMatches(Node current, Node node)
{
if (count == null)
{
int cnt = current.getNodeType();
int nnt = node.getNodeType();
if (cnt != nnt)
{
return false;
}
if (nnt == Node.ELEMENT_NODE || nnt == Node.ATTRIBUTE_NODE)
{
String curi = current.getNamespaceURI();
String nuri = node.getNamespaceURI();
if ((curi == null && nuri != null) ||
(curi != null && !curi.equals(nuri)))
{
return false;
}
String cn = current.getLocalName();
if (cn == null)
{
cn = current.getNodeName();
}
String nn = node.getLocalName();
if (nn == null)
{
nn = node.getNodeName();
}
if (!cn.equals(nn))
{
return false;
}
}
return true;
}
else
{
return count.matches(node);
}
}
boolean fromMatches(Node node)
{
for (Node ctx = node.getParentNode(); ctx != null;
ctx = ctx.getParentNode())
{
if (from.matches(ctx))
{
return true;
}
}
return false;
}
int getIndex(Node current, Node node)
{
int index = 0;
do
{
do
{
node = node.getPreviousSibling();
}
while (node != null && !countMatches(current, node));
index++;
}
while (node != null);
return index;
}
}
@@ -0,0 +1,88 @@
/* NumberNode.java --
Copyright (C) 2004 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 javax.xml.transform.TransformerException;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
/**
* A template node representing the XSL <code>number</code> instruction
* with a <code>value</code> expression.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class NumberNode
extends AbstractNumberNode
{
final Expr value;
NumberNode(Expr value, TemplateNode format, String lang,
int letterValue, String groupingSeparator, int groupingSize)
{
super(format, lang, letterValue, groupingSeparator, groupingSize);
this.value = value;
}
TemplateNode clone(Stylesheet stylesheet)
{
TemplateNode ret = new NumberNode(value.clone(stylesheet),
format, lang, letterValue,
groupingSeparator, groupingSize);
if (children != null)
{
ret.children = children.clone(stylesheet);
}
if (next != null)
{
ret.next = next.clone(stylesheet);
}
return ret;
}
int[] compute(Stylesheet stylesheet, Node context, int pos, int len)
throws TransformerException
{
Object ret = value.evaluate(context, pos, len);
Double d = (ret instanceof Double) ? ((Double) ret) :
new Double(Expr._number(context, ret));
return new int[] { d.intValue() };
}
}
@@ -0,0 +1,94 @@
/* OtherwiseNode.java --
Copyright (C) 2004 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 javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Node;
/**
* A template node representing an XSL <code>otherwise</code> instruction.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class OtherwiseNode
extends TemplateNode
{
TemplateNode clone(Stylesheet stylesheet)
{
TemplateNode ret = new OtherwiseNode();
if (children != null)
{
ret.children = children.clone(stylesheet);
}
if (next != null)
{
ret.next = next.clone(stylesheet);
}
return ret;
}
void doApply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
if (children != null)
{
children.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
if (next != null)
{
next.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
}
public String toString()
{
StringBuffer buf = new StringBuffer(getClass().getName());
buf.append('[');
buf.append(']');
return buf.toString();
}
}
@@ -0,0 +1,198 @@
/* ParameterNode.java --
Copyright (C) 2004 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 java.util.Collections;
import javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
/**
* A template node that sets a variable or parameter during template
* processing.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class ParameterNode
extends TemplateNode
implements Comparable
{
final QName name;
final Expr select;
final int type;
ParameterNode(QName name, Expr select, int type)
{
this.name = name;
this.select = select;
this.type = type;
}
TemplateNode clone(Stylesheet stylesheet)
{
TemplateNode ret = new ParameterNode(name,
select.clone(stylesheet),
type);
if (children != null)
{
ret.children = children.clone(stylesheet);
}
if (next != null)
{
ret.next = next.clone(stylesheet);
}
return ret;
}
void doApply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
// push the variable context
stylesheet.bindings.push(type);
// set the variable
Object value = getValue(stylesheet, mode, context, pos, len);
if (value != null)
{
stylesheet.bindings.set(name, value, type);
if (stylesheet.debug)
{
System.err.println(this + ": set to " + value);
}
}
// variable and param don't process children as such
// all subsequent instructions are processed with that variable context
if (next != null)
{
next.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
// pop the variable context
stylesheet.bindings.pop(type);
}
Object getValue(Stylesheet stylesheet, QName mode,
Node context, int pos, int len)
throws TransformerException
{
if (select != null)
{
return select.evaluate(context, pos, len);
}
else if (children != null)
{
Document doc = (context instanceof Document) ? (Document) context :
context.getOwnerDocument();
DocumentFragment fragment = doc.createDocumentFragment();
children.apply(stylesheet, mode, context, pos, len, fragment, null);
return Collections.singleton(fragment);
}
else
{
return null;
}
}
public boolean references(QName var)
{
if (select != null && select.references(var))
{
return true;
}
return super.references(var);
}
public int compareTo(Object other)
{
if (other instanceof ParameterNode)
{
ParameterNode pn = (ParameterNode) other;
boolean r1 = references(pn.name);
boolean r2 = pn.references(name);
if (r1 && r2)
{
throw new IllegalArgumentException("circular definitions");
}
if (r1)
{
return 1;
}
if (r2)
{
return -1;
}
}
return 0;
}
public String toString()
{
StringBuffer buf = new StringBuffer(getClass().getName());
buf.append('[');
buf.append("name=");
buf.append(name);
if (select != null)
{
buf.append(",select=");
buf.append(select);
}
buf.append(",type=");
switch (type)
{
case Bindings.VARIABLE:
buf.append("variable");
break;
case Bindings.PARAM:
buf.append("param");
break;
case Bindings.WITH_PARAM:
buf.append("with-param");
break;
}
buf.append(']');
return buf.toString();
}
}
@@ -0,0 +1,126 @@
/* ProcessingInstructionNode.java --
Copyright (C) 2004 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 javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Node;
import org.w3c.dom.ProcessingInstruction;
import gnu.xml.xpath.Expr;
/**
* A template node representing the XSL <code>processing-instruction</code>
* instruction.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class ProcessingInstructionNode
extends TemplateNode
{
final String name;
ProcessingInstructionNode(String name)
{
this.name = name;
}
TemplateNode clone(Stylesheet stylesheet)
{
TemplateNode ret = new ProcessingInstructionNode(name);
if (children != null)
{
ret.children = children.clone(stylesheet);
}
if (next != null)
{
ret.next = next.clone(stylesheet);
}
return ret;
}
void doApply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
String data = null;
Document doc = (parent instanceof Document) ? (Document) parent :
parent.getOwnerDocument();
if (children != null)
{
// Create a document fragment to hold the text
DocumentFragment fragment = doc.createDocumentFragment();
// Apply children to the fragment
children.apply(stylesheet, mode,
context, pos, len,
fragment, null);
// Use XPath string-value of fragment
data = Expr.stringValue(fragment);
}
ProcessingInstruction pi = doc.createProcessingInstruction(name, data);
// Insert into result tree
if (nextSibling != null)
{
parent.insertBefore(pi, nextSibling);
}
else
{
parent.appendChild(pi);
}
if (next != null)
{
next.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
}
public String toString()
{
StringBuffer buf = new StringBuffer(getClass().getName());
buf.append('[');
buf.append("name=");
buf.append(name);
buf.append(']');
return buf.toString();
}
}
@@ -0,0 +1,305 @@
/* SAXSerializer.java --
Copyright (C) 2004 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 java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import org.w3c.dom.Attr;
import org.w3c.dom.DocumentType;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.ext.LexicalHandler;
/**
* Serializes a DOM node to a sequence of SAX events.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
class SAXSerializer
implements Attributes
{
transient NamedNodeMap attrs;
transient LinkedList namespaces = new LinkedList();
boolean isDefined(String prefix, String uri)
{
for (Iterator i = namespaces.iterator(); i.hasNext(); )
{
HashMap ctx = (HashMap) i.next();
if (uri.equals(ctx.get(prefix)))
{
return true;
}
}
return false;
}
void define(String prefix, String uri)
{
for (Iterator i = namespaces.iterator(); i.hasNext(); )
{
HashMap ctx = (HashMap) i.next();
if (ctx.containsKey(prefix))
{
HashMap newCtx = new HashMap();
newCtx.put(prefix, uri);
namespaces.addFirst(newCtx);
return;
}
}
HashMap ctx;
if (namespaces.isEmpty())
{
ctx = new HashMap();
namespaces.add(ctx);
}
else
{
ctx = (HashMap) namespaces.getFirst();
}
ctx.put(prefix, uri);
}
void undefine(String prefix, String uri)
{
for (Iterator i = namespaces.iterator(); i.hasNext(); )
{
HashMap ctx = (HashMap) i.next();
if (uri.equals(ctx.get(prefix)))
{
ctx.remove(prefix);
if (ctx.isEmpty())
{
namespaces.remove(ctx);
}
return;
}
}
}
public int getLength()
{
return attrs.getLength();
}
public String getURI(int index)
{
return attrs.item(index).getNamespaceURI();
}
public String getLocalName(int index)
{
return attrs.item(index).getLocalName();
}
public String getQName(int index)
{
return attrs.item(index).getNodeName();
}
public String getType(int index)
{
Attr attr = (Attr) attrs.item(index);
return attr.isId() ? "ID" : "CDATA";
}
public String getValue(int index)
{
return attrs.item(index).getNodeValue();
}
public int getIndex(String uri, String localName)
{
int len = attrs.getLength();
for (int i = 0; i < len; i++)
{
Node attr = attrs.item(i);
String a_uri = attr.getNamespaceURI();
String a_localName = attr.getLocalName();
if (((a_uri == null && uri == null) ||
(a_uri != null && a_uri.equals(uri))) &&
a_localName.equals(localName))
{
return i;
}
}
return -1;
}
public int getIndex(String qName)
{
int len = attrs.getLength();
for (int i = 0; i < len; i++)
{
Node attr = attrs.item(i);
String a_name = attr.getNodeName();
if (a_name.equals(qName))
{
return i;
}
}
return -1;
}
public String getType(String uri, String localName)
{
Attr attr = (Attr) attrs.getNamedItemNS(uri, localName);
return attr.isId() ? "ID" : "CDATA";
}
public String getType(String qName)
{
Attr attr = (Attr) attrs.getNamedItem(qName);
return attr.isId() ? "ID" : "CDATA";
}
public String getValue(String uri, String localName)
{
return attrs.getNamedItemNS(uri, localName).getNodeValue();
}
public String getValue(String qName)
{
return attrs.getNamedItem(qName).getNodeValue();
}
void serialize(Node node, ContentHandler ch, LexicalHandler lh)
throws SAXException
{
attrs = node.getAttributes();
Node children;
Node next = node.getNextSibling();
switch (node.getNodeType())
{
case Node.ELEMENT_NODE:
String uri = node.getNamespaceURI();
String prefix = node.getPrefix();
boolean defined = isDefined(prefix, uri);
if (!defined)
{
define(prefix, uri);
ch.startPrefixMapping(prefix, uri);
}
String localName = node.getLocalName();
String qName = node.getNodeName();
ch.startElement(uri, localName, qName, this);
children = node.getFirstChild();
if (children != null)
{
serialize(children, ch, lh);
}
ch.endElement(uri, localName, qName);
if (!defined)
{
ch.endPrefixMapping(prefix);
undefine(prefix, uri);
}
break;
case Node.TEXT_NODE:
char[] chars = node.getNodeValue().toCharArray();
ch.characters(chars, 0, chars.length);
break;
case Node.CDATA_SECTION_NODE:
char[] cdata = node.getNodeValue().toCharArray();
if (lh != null)
{
lh.startCDATA();
ch.characters(cdata, 0, cdata.length);
lh.endCDATA();
}
else
{
ch.characters(cdata, 0, cdata.length);
}
break;
case Node.COMMENT_NODE:
if (lh != null)
{
char[] comment = node.getNodeValue().toCharArray();
lh.comment(comment, 0, comment.length);
}
break;
case Node.DOCUMENT_NODE:
case Node.DOCUMENT_FRAGMENT_NODE:
ch.startDocument();
children = node.getFirstChild();
if (children != null)
{
serialize(children, ch, lh);
}
ch.endDocument();
break;
case Node.DOCUMENT_TYPE_NODE:
if (lh != null)
{
DocumentType doctype = (DocumentType) node;
String publicId = doctype.getPublicId();
String systemId = doctype.getSystemId();
lh.startDTD(node.getNodeName(), publicId, systemId);
NamedNodeMap entities = doctype.getEntities();
int len = entities.getLength();
for (int i = 0; i < len; i++)
{
Node entity = entities.item(i);
String entityName = entity.getNodeName();
lh.startEntity(entityName);
lh.endEntity(entityName);
}
lh.endDTD();
}
break;
case Node.PROCESSING_INSTRUCTION_NODE:
ch.processingInstruction(node.getNodeName(), node.getNodeValue());
break;
case Node.ENTITY_REFERENCE_NODE:
ch.skippedEntity(node.getNodeName());
break;
}
attrs = null;
if (next != null)
{
serialize(next, ch, lh);
}
}
}
@@ -0,0 +1,179 @@
/* SortKey.java --
Copyright (C) 2004 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 javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
/**
* An XSL sort key.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class SortKey
{
static final int DEFAULT = 0;
static final int UPPER_FIRST = 1;
static final int LOWER_FIRST = 2;
final Expr select;
final TemplateNode langTemplate;
final TemplateNode dataTypeTemplate;
final TemplateNode orderTemplate;
final TemplateNode caseOrderTemplate;
transient String lang;
transient String dataType;
transient boolean descending;
transient int caseOrder;
SortKey(Expr select, TemplateNode lang, TemplateNode dataType,
TemplateNode order, TemplateNode caseOrder)
{
this.select = select;
this.langTemplate = lang;
this.dataTypeTemplate = dataType;
this.orderTemplate = order;
this.caseOrderTemplate = caseOrder;
}
String key(Node node)
{
Object ret = select.evaluate(node, 1, 1);
if (ret instanceof String)
{
return (String) ret;
}
else
{
return Expr._string(node, ret);
}
}
/**
* Prepare for a sort.
* This sets all transient variables from their AVTs.
*/
void init(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
Document doc = (context instanceof Document) ? (Document) context :
context.getOwnerDocument();
if (langTemplate == null)
{
lang = null;
}
else
{
DocumentFragment fragment = doc.createDocumentFragment();
langTemplate.apply(stylesheet, mode, context, pos, len,
fragment, null);
lang = Expr.stringValue(fragment);
}
if (dataTypeTemplate == null)
{
dataType = "text";
}
else
{
DocumentFragment fragment = doc.createDocumentFragment();
dataTypeTemplate.apply(stylesheet, mode, context, pos, len,
fragment, null);
dataType = Expr.stringValue(fragment);
}
if (orderTemplate == null)
{
descending = false;
}
else
{
DocumentFragment fragment = doc.createDocumentFragment();
orderTemplate.apply(stylesheet, mode, context, pos, len,
fragment, null);
String order = Expr.stringValue(fragment);
descending = "descending".equals(order);
}
if (caseOrderTemplate == null)
{
caseOrder = DEFAULT;
}
else
{
DocumentFragment fragment = doc.createDocumentFragment();
caseOrderTemplate.apply(stylesheet, mode, context, pos, len,
fragment, null);
String co = Expr.stringValue(fragment);
caseOrder = "upper-first".equals(co) ? UPPER_FIRST :
"lower-first".equals(co) ? LOWER_FIRST :
DEFAULT;
}
}
boolean references(QName var)
{
if (select != null && select.references(var))
{
return true;
}
if (langTemplate != null && langTemplate.references(var))
{
return true;
}
if (dataTypeTemplate != null && dataTypeTemplate.references(var))
{
return true;
}
if (orderTemplate != null && orderTemplate.references(var))
{
return true;
}
if (caseOrderTemplate != null && caseOrderTemplate.references(var))
{
return true;
}
return false;
}
}
@@ -0,0 +1,762 @@
/* StreamSerializer.java --
Copyright (C) 2004 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 java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import javax.xml.XMLConstants;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
/**
* Serializes a DOM node to an output stream.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
public class StreamSerializer
{
static final int SPACE = 0x20;
static final int BANG = 0x21; // !
static final int APOS = 0x27; // '
static final int SLASH = 0x2f; // /
static final int BRA = 0x3c; // <
static final int KET = 0x3e; // >
static final int EQ = 0x3d; // =
/**
* HTML 4.01 boolean attributes
*/
static final Map HTML_BOOLEAN_ATTRIBUTES = new HashMap();
static
{
HashSet set;
set = new HashSet();
set.add("nohref");
HTML_BOOLEAN_ATTRIBUTES.put("area", set);
set = new HashSet();
set.add("ismap");
HTML_BOOLEAN_ATTRIBUTES.put("img", set);
set = new HashSet();
set.add("declare");
HTML_BOOLEAN_ATTRIBUTES.put("object", set);
set = new HashSet();
set.add("noshade");
HTML_BOOLEAN_ATTRIBUTES.put("hr", set);
set = new HashSet();
set.add("compact");
HTML_BOOLEAN_ATTRIBUTES.put("dl", set);
HTML_BOOLEAN_ATTRIBUTES.put("ol", set);
HTML_BOOLEAN_ATTRIBUTES.put("ul", set);
HTML_BOOLEAN_ATTRIBUTES.put("dir", set);
HTML_BOOLEAN_ATTRIBUTES.put("menu", set);
set = new HashSet();
set.add("checked");
set.add("disabled");
set.add("readonly");
set.add("ismap");
HTML_BOOLEAN_ATTRIBUTES.put("input", set);
set = new HashSet();
set.add("multiple");
set.add("disabled");
HTML_BOOLEAN_ATTRIBUTES.put("select", set);
set = new HashSet();
set.add("disabled");
HTML_BOOLEAN_ATTRIBUTES.put("optgroup", set);
set = new HashSet();
set.add("selected");
set.add("disabled");
HTML_BOOLEAN_ATTRIBUTES.put("option", set);
set = new HashSet();
set.add("disabled");
set.add("readonly");
HTML_BOOLEAN_ATTRIBUTES.put("textarea", set);
set = new HashSet();
set.add("disabled");
HTML_BOOLEAN_ATTRIBUTES.put("button", set);
set = new HashSet();
set.add("nowrap");
HTML_BOOLEAN_ATTRIBUTES.put("th", set);
HTML_BOOLEAN_ATTRIBUTES.put("td", set);
set = new HashSet();
set.add("noresize");
HTML_BOOLEAN_ATTRIBUTES.put("frame", set);
set = new HashSet();
set.add("defer");
HTML_BOOLEAN_ATTRIBUTES.put("script", set);
}
protected final String encoding;
final Charset charset;
final CharsetEncoder encoder;
final int mode;
final Map namespaces;
protected String eol;
Collection cdataSectionElements = Collections.EMPTY_SET;
protected boolean discardDefaultContent;
protected boolean xmlDeclaration = true;
public StreamSerializer()
{
this(Stylesheet.OUTPUT_XML, null, null);
}
public StreamSerializer(String encoding)
{
this(Stylesheet.OUTPUT_XML, encoding, null);
}
public StreamSerializer(int mode, String encoding, String eol)
{
this.mode = mode;
if (encoding == null)
{
encoding = "UTF-8";
}
this.encoding = encoding.intern();
charset = Charset.forName(this.encoding);
encoder = charset.newEncoder();
this.eol = (eol != null) ? eol : System.getProperty("line.separator");
namespaces = new HashMap();
}
void setCdataSectionElements(Collection c)
{
cdataSectionElements = c;
}
public void serialize(final Node node, final OutputStream out)
throws IOException
{
serialize(node, out, false);
}
void serialize(Node node, final OutputStream out,
boolean convertToCdata)
throws IOException
{
while (node != null)
{
Node next = node.getNextSibling();
doSerialize(node, out, convertToCdata);
node = next;
}
}
private void doSerialize(final Node node, final OutputStream out,
boolean convertToCdata)
throws IOException
{
if (out == null)
{
throw new NullPointerException("no output stream");
}
String value, prefix;
Node children;
String uri = node.getNamespaceURI();
boolean defined = false;
short nt = node.getNodeType();
if (convertToCdata && nt == Node.TEXT_NODE)
{
nt = Node.CDATA_SECTION_NODE;
}
switch (nt)
{
case Node.ATTRIBUTE_NODE:
prefix = node.getPrefix();
if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri) ||
XMLConstants.XMLNS_ATTRIBUTE.equals(prefix) ||
(prefix != null && prefix.startsWith("xmlns:")))
{
String nsuri = node.getNodeValue();
if (isDefined(nsuri))
{
break;
}
String name = node.getLocalName();
if (name == null)
{
name = node.getNodeName();
}
define(nsuri, name);
}
else if (uri != null && !isDefined(uri))
{
prefix = define(uri, prefix);
String nsname = (prefix == null) ? "xmlns" : "xmlns:" + prefix;
out.write(SPACE);
out.write(encodeText(nsname));
out.write(EQ);
String nsvalue = "'" + encode(uri, true, true) + "'";
out.write(nsvalue.getBytes(encoding));
defined = true;
}
out.write(SPACE);
String a_nodeName = node.getNodeName();
out.write(encodeText(a_nodeName));
String a_nodeValue = node.getNodeValue();
if (mode == Stylesheet.OUTPUT_HTML &&
a_nodeName.equals(a_nodeValue) &&
isHTMLBoolean((Attr) node, a_nodeName))
{
break;
}
out.write(EQ);
value = "'" + encode(a_nodeValue, true, true) + "'";
out.write(encodeText(value));
break;
case Node.ELEMENT_NODE:
value = node.getNodeName();
out.write(BRA);
out.write(encodeText(value));
if (uri != null && !isDefined(uri))
{
prefix = define(uri, node.getPrefix());
String nsname = (prefix == null) ? "xmlns" : "xmlns:" + prefix;
out.write(SPACE);
out.write(encodeText(nsname));
out.write(EQ);
String nsvalue = "'" + encode(uri, true, true) + "'";
out.write(encodeText(nsvalue));
defined = true;
}
NamedNodeMap attrs = node.getAttributes();
if (attrs != null)
{
int len = attrs.getLength();
for (int i = 0; i < len; i++)
{
Attr attr = (Attr) attrs.item(i);
if (discardDefaultContent && !attr.getSpecified())
{
// NOOP
}
else
{
serialize(attr, out, false);
}
}
}
convertToCdata = cdataSectionElements.contains(value);
children = node.getFirstChild();
if (children == null)
{
out.write(SLASH);
out.write(KET);
}
else
{
out.write(KET);
serialize(children, out, convertToCdata);
out.write(BRA);
out.write(SLASH);
out.write(encodeText(value));
out.write(KET);
}
break;
case Node.TEXT_NODE:
value = node.getNodeValue();
if (!"yes".equals(node.getUserData("disable-output-escaping")))
{
value = encode(value, false, false);
}
out.write(encodeText(value));
break;
case Node.CDATA_SECTION_NODE:
value = "<![CDATA[" + node.getNodeValue() + "]]>";
out.write(encodeText(value));
break;
case Node.COMMENT_NODE:
value = "<!--" + node.getNodeValue() + "-->";
out.write(encodeText(value));
Node cp = node.getParentNode();
if (cp != null && cp.getNodeType() == Node.DOCUMENT_NODE)
{
out.write(encodeText(eol));
}
break;
case Node.DOCUMENT_NODE:
case Node.DOCUMENT_FRAGMENT_NODE:
if (mode == Stylesheet.OUTPUT_XML)
{
if ("UTF-16".equalsIgnoreCase(encoding))
{
out.write(0xfe);
out.write(0xff);
}
if (!"yes".equals(node.getUserData("omit-xml-declaration")) &&
xmlDeclaration)
{
Document doc = (node instanceof Document) ?
(Document) node : null;
String version = (doc != null) ? doc.getXmlVersion() : null;
if (version == null)
{
version = (String) node.getUserData("version");
}
if (version == null)
{
version = "1.0";
}
out.write(BRA);
out.write(0x3f);
out.write("xml version='".getBytes("US-ASCII"));
out.write(version.getBytes("US-ASCII"));
out.write(APOS);
if (!("UTF-8".equalsIgnoreCase(encoding)))
{
out.write(" encoding='".getBytes("US-ASCII"));
out.write(encoding.getBytes("US-ASCII"));
out.write(APOS);
}
if ((doc != null && doc.getXmlStandalone()) ||
"yes".equals(node.getUserData("standalone")))
{
out.write(" standalone='yes'".getBytes("US-ASCII"));
}
out.write(0x3f);
out.write(KET);
out.write(encodeText(eol));
}
// TODO warn if not outputting the declaration would be a
// problem
}
else if (mode == Stylesheet.OUTPUT_HTML)
{
// Ensure that encoding is accessible
String mediaType = (String) node.getUserData("media-type");
if (mediaType == null)
{
mediaType = "text/html";
}
String contentType = mediaType + "; charset=" +
((encoding.indexOf(' ') != -1) ?
"\"" + encoding + "\"" :
encoding);
Document doc = (node instanceof Document) ? (Document) node :
node.getOwnerDocument();
Node html = null;
for (Node ctx = node.getFirstChild(); ctx != null;
ctx = ctx.getNextSibling())
{
if (ctx.getNodeType() == Node.ELEMENT_NODE)
{
html = ctx;
break;
}
}
if (html == null)
{
html = doc.createElement("html");
node.appendChild(html);
}
Node head = null;
for (Node ctx = html.getFirstChild(); ctx != null;
ctx = ctx.getNextSibling())
{
if (ctx.getNodeType() == Node.ELEMENT_NODE)
{
String name = ctx.getLocalName();
if (name == null)
{
name = ctx.getNodeName();
}
if ("head".equalsIgnoreCase(name))
{
head = ctx;
break;
}
}
}
if (head == null)
{
head = doc.createElement("head");
Node c1 = null;
for (Node ctx = html.getFirstChild(); ctx != null;
ctx = ctx.getNextSibling())
{
if (ctx.getNodeType() == Node.ELEMENT_NODE)
{
c1 = ctx;
break;
}
}
if (c1 != null)
{
html.insertBefore(head, c1);
}
else
{
html.appendChild(head);
}
}
Node meta = null;
Node metaContent = null;
for (Node ctx = head.getFirstChild(); ctx != null;
ctx = ctx.getNextSibling())
{
if (ctx.getNodeType() == Node.ELEMENT_NODE)
{
String name = ctx.getLocalName();
if (name == null)
{
name = ctx.getNodeName();
}
if ("meta".equalsIgnoreCase(name))
{
NamedNodeMap metaAttrs = ctx.getAttributes();
int len = metaAttrs.getLength();
String httpEquiv = null;
Node content = null;
for (int i = 0; i < len; i++)
{
Node attr = metaAttrs.item(i);
String attrName = attr.getNodeName();
if ("http-equiv".equalsIgnoreCase(attrName))
{
httpEquiv = attr.getNodeValue();
}
else if ("content".equalsIgnoreCase(attrName))
{
content = attr;
}
}
if ("Content-Type".equalsIgnoreCase(httpEquiv))
{
meta = ctx;
metaContent = content;
break;
}
}
}
}
if (meta == null)
{
meta = doc.createElement("meta");
// Insert first
Node first = head.getFirstChild();
if (first == null)
{
head.appendChild(meta);
}
else
{
head.insertBefore(meta, first);
}
Node metaHttpEquiv = doc.createAttribute("http-equiv");
meta.getAttributes().setNamedItem(metaHttpEquiv);
metaHttpEquiv.setNodeValue("Content-Type");
}
if (metaContent == null)
{
metaContent = doc.createAttribute("content");
meta.getAttributes().setNamedItem(metaContent);
}
metaContent.setNodeValue(contentType);
// phew
}
children = node.getFirstChild();
if (children != null)
{
serialize(children, out, convertToCdata);
}
break;
case Node.DOCUMENT_TYPE_NODE:
DocumentType doctype = (DocumentType) node;
out.write(BRA);
out.write(BANG);
out.write(encodeText("DOCTYPE "));
value = doctype.getNodeName();
out.write(encodeText(value));
String publicId = doctype.getPublicId();
if (publicId != null)
{
out.write(encodeText(" PUBLIC "));
out.write(APOS);
out.write(encodeText(publicId));
out.write(APOS);
}
String systemId = doctype.getSystemId();
if (systemId != null)
{
out.write(encodeText(" SYSTEM "));
out.write(APOS);
out.write(encodeText(systemId));
out.write(APOS);
}
String internalSubset = doctype.getInternalSubset();
if (internalSubset != null)
{
out.write(encodeText(internalSubset));
}
out.write(KET);
out.write(eol.getBytes(encoding));
break;
case Node.ENTITY_REFERENCE_NODE:
value = "&" + node.getNodeValue() + ";";
out.write(encodeText(value));
break;
case Node.PROCESSING_INSTRUCTION_NODE:
value = "<?" + node.getNodeName() + " " + node.getNodeValue() + "?>";
out.write(encodeText(value));
Node pp = node.getParentNode();
if (pp != null && pp.getNodeType() == Node.DOCUMENT_NODE)
{
out.write(encodeText(eol));
}
break;
}
if (defined)
{
undefine(uri);
}
}
boolean isDefined(String uri)
{
return XMLConstants.XML_NS_URI.equals(uri) ||
XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri) ||
namespaces.containsKey(uri);
}
String define(String uri, String prefix)
{
while (namespaces.containsValue(prefix))
{
// Fabricate new prefix
prefix = prefix + "_";
}
namespaces.put(uri, prefix);
return prefix;
}
void undefine(String uri)
{
namespaces.remove(uri);
}
final byte[] encodeText(String text)
throws IOException
{
encoder.reset();
if (!encoder.canEncode(text))
{
// Check each character
StringBuffer buf = new StringBuffer();
int len = text.length();
for (int i = 0; i < len; i++)
{
char c = text.charAt(i);
if (encoder.canEncode(c))
{
buf.append(c);
}
else
{
// Replace with character entity reference
String hex = Integer.toHexString((int) c);
buf.append("&#x");
buf.append(hex);
buf.append(';');
}
}
text = buf.toString();
}
ByteBuffer encoded = encoder.encode(CharBuffer.wrap(text));
int len = encoded.limit() - encoded.position();
if (encoded.hasArray())
{
byte[] ret = encoded.array();
if (ret.length > len)
{
// Why?
byte[] ret2 = new byte[len];
System.arraycopy(ret, 0, ret2, 0, len);
ret = ret2;
}
return ret;
}
encoded.flip();
byte[] ret = new byte[len];
encoded.get(ret, 0, len);
return ret;
}
String encode(String text, boolean encodeCtl, boolean inAttr)
{
int len = text.length();
StringBuffer buf = null;
for (int i = 0; i < len; i++)
{
char c = text.charAt(i);
if (c == '<')
{
if (buf == null)
{
buf = new StringBuffer(text.substring(0, i));
}
buf.append("&lt;");
}
else if (c == '>')
{
if (buf == null)
{
buf = new StringBuffer(text.substring(0, i));
}
buf.append("&gt;");
}
else if (c == '&')
{
if (mode == Stylesheet.OUTPUT_HTML && (i + 1) < len &&
text.charAt(i + 1) == '{')
{
if (buf != null)
{
buf.append(c);
}
}
else
{
if (buf == null)
{
buf = new StringBuffer(text.substring(0, i));
}
buf.append("&amp;");
}
}
else if (c == '\'' && inAttr)
{
if (buf == null)
{
buf = new StringBuffer(text.substring(0, i));
}
buf.append("&apos;");
}
else if (c == '"' && inAttr)
{
if (buf == null)
{
buf = new StringBuffer(text.substring(0, i));
}
buf.append("&quot;");
}
else if (encodeCtl)
{
if (c < 0x20)
{
if (buf == null)
{
buf = new StringBuffer(text.substring(0, i));
}
buf.append('&');
buf.append('#');
buf.append((int) c);
buf.append(';');
}
else if (buf != null)
{
buf.append(c);
}
}
else if (buf != null)
{
buf.append(c);
}
}
return (buf == null) ? text : buf.toString();
}
String toString(Node node)
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
try
{
serialize(node, out);
return new String(out.toByteArray(), encoding);
}
catch (IOException e)
{
throw new RuntimeException(e.getMessage());
}
}
boolean isHTMLBoolean(Attr attr, String attrName)
{
attrName = attrName.toLowerCase();
Node element = attr.getOwnerElement();
String elementName = element.getLocalName();
if (elementName == null)
{
elementName = element.getNodeName();
}
elementName = elementName.toLowerCase();
Collection attributes =
(Collection) HTML_BOOLEAN_ATTRIBUTES.get(elementName);
return (attributes != null && attributes.contains(attrName));
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,141 @@
/* SystemPropertyFunction.java --
Copyright (C) 2004 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 java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.xpath.XPathFunction;
import javax.xml.xpath.XPathFunctionException;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
import gnu.xml.xpath.Function;
/**
* The XSLT <code>system-property()</code>function.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class SystemPropertyFunction
extends Expr
implements XPathFunction, Function
{
List args;
public Object evaluate(List args)
throws XPathFunctionException
{
String name = (String) args.get(0);
return systemProperty(QName.valueOf(name));
}
public void setArguments(List args)
{
this.args = args;
}
public Object evaluate(Node context, int pos, int len)
{
int arity = args.size();
List values = new ArrayList(arity);
for (int i = 0; i < arity; i++)
{
Expr arg = (Expr) args.get(i);
values.add(arg.evaluate(context, pos, len));
}
String name = _string(context, values.get(0));
return systemProperty(QName.valueOf(name));
}
Object systemProperty(QName name)
{
String localName = name.getLocalPart();
String prefix = name.getPrefix();
String uri = name.getNamespaceURI();
if (Stylesheet.XSL_NS.equals(uri) ||
"xsl".equals(prefix))
{
if ("version".equals(localName))
{
return new Double(1.0d);
}
else if ("vendor".equals(localName))
{
return "The Free Software Foundation";
}
else if ("vendor-url".equals(localName))
{
return "http://www.gnu.org/";
}
else
{
return "";
}
}
return System.getProperty(localName);
}
public Expr clone(Object context)
{
SystemPropertyFunction f = new SystemPropertyFunction();
int len = args.size();
List args2 = new ArrayList(len);
for (int i = 0; i < len; i++)
{
args2.add(((Expr) args.get(i)).clone(context));
}
f.setArguments(args2);
return f;
}
public boolean references(QName var)
{
for (Iterator i = args.iterator(); i.hasNext(); )
{
if (((Expr) i.next()).references(var))
{
return true;
}
}
return false;
}
}
@@ -0,0 +1,252 @@
/* Template.java --
Copyright (C) 2004 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 java.io.PrintStream;
import javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Node;
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.Test;
/**
* A template in an XSL stylesheet.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
class Template
implements Comparable
{
static final double DEFAULT_PRIORITY = 0.5d;
final Stylesheet stylesheet;
final QName name;
final Pattern match;
final TemplateNode node;
final double priority;
final int precedence;
final QName mode;
Template(Stylesheet stylesheet,
QName name, Pattern match, TemplateNode node,
int precedence, double priority, QName mode)
{
this.stylesheet = stylesheet;
this.name = name;
this.match = match;
this.node = node;
// adjust priority if necessary
// see XSLT section 5.5
Test test = getNodeTest(match);
if (test != null)
{
if (test instanceof NameTest)
{
NameTest nameTest = (NameTest) test;
if (nameTest.matchesAny() ||
nameTest.matchesAnyLocalName())
{
priority = -0.25d;
}
else
{
priority = 0.0d;
}
}
else
{
NodeTypeTest nodeTypeTest = (NodeTypeTest) test;
if (nodeTypeTest.getNodeType() ==
Node.PROCESSING_INSTRUCTION_NODE &&
nodeTypeTest.getData() != null)
{
priority = 0.0d;
}
else
{
priority = -0.5d;
}
}
}
this.precedence = precedence;
this.priority = priority;
this.mode = mode;
}
Template clone(Stylesheet stylesheet)
{
// FIXME by cloning we lose the imports() functionality, so
// apply-imports will be broken.
return new Template(stylesheet,
name,
(match == null) ? null :
(Pattern) match.clone(stylesheet),
(node == null) ? null : node.clone(stylesheet),
precedence,
priority,
mode);
}
public int compareTo(Object other)
{
if (other instanceof Template)
{
Template t = (Template) other;
int d = t.precedence - precedence;
if (d != 0)
{
return d;
}
double d2 = t.priority - priority;
if (d2 != 0.0d)
{
return (int) Math.round(d2 * 1000.0d);
}
}
return 0;
}
Test getNodeTest(Expr expr)
{
if (expr instanceof Selector)
{
Selector selector = (Selector) expr;
Test[] tests = selector.getTests();
if (tests.length > 0)
{
return tests[0];
}
}
return null;
}
boolean matches(QName mode, Node node)
{
if ((mode == null && this.mode != null) ||
(mode != null && !mode.equals(this.mode)))
{
return false;
}
if (match == null)
{
return false;
}
return match.matches(node);
}
boolean matches(QName name)
{
return name.equals(this.name);
}
boolean imports(Template other)
{
for (Stylesheet ctx = other.stylesheet.parent;
ctx != null;
ctx = ctx.parent)
{
if (ctx == stylesheet)
{
return true;
}
}
return false;
}
/**
* @param stylesheet the stylesheet
* @param parent the parent of result nodes
* @param context the context node in the source document
* @param pos the context position
* @param len the context size
* @param nextSibling if non-null, add result nodes before this node
*/
void apply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
System.err.println("...applying " + toString() + " to " + context);
if (node != null)
{
node.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
}
public String toString()
{
StringBuffer buf = new StringBuffer(getClass().getName());
buf.append('[');
if (name != null)
{
buf.append("name=");
buf.append(name);
}
else if (match != null)
{
buf.append("match=");
buf.append(match);
}
if (mode != null)
{
buf.append(",mode=");
buf.append(mode);
}
buf.append(']');
return buf.toString();
//return (name != null) ? name.toString() : match.toString();
}
void list(PrintStream out)
{
out.println(toString());
if (node != null)
{
node.list(1, out, true);
}
}
}
@@ -0,0 +1,124 @@
/* TemplateNode.java --
Copyright (C) 2004 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 java.io.PrintStream;
import java.util.Comparator;
import javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Node;
import gnu.xml.xpath.DocumentOrderComparator;
/**
* Wrapper for a source node in a template.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
abstract class TemplateNode
{
static final Comparator documentOrderComparator =
new DocumentOrderComparator();
TemplateNode children;
TemplateNode next;
final void apply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
if (stylesheet.terminated)
{
return;
}
if (Thread.currentThread().isInterrupted())
{
// Try to head off any infinite loops at the pass
return;
}
if (stylesheet.debug)
{
System.err.println("Applying " + toString());
System.err.println("\twith context=" + context + ", pos=" + pos +
", len=" + len);
}
doApply(stylesheet, mode, context, pos, len, parent, nextSibling);
}
abstract void doApply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException;
abstract TemplateNode clone(Stylesheet stylesheet);
public boolean references(QName var)
{
if (children != null && children.references(var))
{
return true;
}
if (next != null && next.references(var))
{
return true;
}
return false;
}
/**
* Debugging
*/
void list(int depth, PrintStream out, boolean listNext)
{
for (int i = 0; i < depth; i++)
{
out.print(" ");
}
out.println(toString());
if (children != null)
{
children.list(depth + 1, out, true);
}
if (listNext && next != null)
{
next.list(depth, out, listNext);
}
}
}
@@ -0,0 +1,80 @@
/* TemplatesImpl.java --
Copyright (C) 2004 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 java.util.Properties;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
/**
* GNU precompiled stylesheet implementation.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
class TemplatesImpl
implements Templates
{
final TransformerFactoryImpl factory;
final Stylesheet stylesheet;
final Properties outputProperties;
TemplatesImpl(TransformerFactoryImpl factory, Stylesheet stylesheet)
{
this.factory = factory;
this.stylesheet = stylesheet;
outputProperties = new TransformerOutputProperties(stylesheet);
}
public Transformer newTransformer()
throws TransformerConfigurationException
{
Stylesheet stylesheet = (Stylesheet) this.stylesheet.clone();
TransformerImpl transformer =
new TransformerImpl(factory, stylesheet, outputProperties);
stylesheet.transformer = transformer;
return transformer;
}
public Properties getOutputProperties()
{
return (Properties) outputProperties.clone();
}
}
@@ -0,0 +1,119 @@
/* TextNode.java --
Copyright (C) 2004 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 javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
import gnu.xml.xpath.Expr;
/**
* A template node representing the XSL <code>text</code> instruction.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class TextNode
extends TemplateNode
{
final boolean disableOutputEscaping;
TextNode(boolean disableOutputEscaping)
{
this.disableOutputEscaping = disableOutputEscaping;
}
TemplateNode clone(Stylesheet stylesheet)
{
TemplateNode ret = new TextNode(disableOutputEscaping);
if (children != null)
{
ret.children = children.clone(stylesheet);
}
if (next != null)
{
ret.next = next.clone(stylesheet);
}
return ret;
}
void doApply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
String value = "";
Document doc = (parent instanceof Document) ? (Document) parent :
parent.getOwnerDocument();
if (children != null)
{
// Create a document fragment to hold the text
DocumentFragment fragment = doc.createDocumentFragment();
// Apply children to the fragment
children.apply(stylesheet, mode,
context, pos, len,
fragment, null);
// Use XPath string-value of fragment
value = Expr.stringValue(fragment);
}
Text text = doc.createTextNode(value);
if (disableOutputEscaping)
{
text.setUserData("disable-output-escaping", "yes", stylesheet);
}
// Insert into result tree
if (nextSibling != null)
{
parent.insertBefore(text, nextSibling);
}
else
{
parent.appendChild(text);
}
if (next != null)
{
next.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
}
}
@@ -0,0 +1,345 @@
/* TransformerFactoryImpl.java --
Copyright (C) 2004 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 java.io.IOException;
import java.net.URL;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Properties;
import javax.xml.transform.ErrorListener;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.URIResolver;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import gnu.xml.dom.DomDocument;
/**
* GNU transformer factory implementation.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
public class TransformerFactoryImpl
extends TransformerFactory
{
final XPathFactory xpathFactory;
final XSLURIResolver resolver;
ErrorListener userListener;
URIResolver userResolver;
public TransformerFactoryImpl()
{
xpathFactory = new gnu.xml.xpath.XPathFactoryImpl();
resolver = new XSLURIResolver();
}
public Transformer newTransformer(Source source)
throws TransformerConfigurationException
{
Stylesheet stylesheet = newStylesheet(source, 0, null);
Properties outputProperties =
new TransformerOutputProperties(stylesheet);
TransformerImpl transformer =
new TransformerImpl(this, stylesheet, outputProperties);
stylesheet.transformer = transformer;
return transformer;
}
public Transformer newTransformer()
throws TransformerConfigurationException
{
return new TransformerImpl(this, null, new Properties());
}
public Templates newTemplates(Source source)
throws TransformerConfigurationException
{
Stylesheet stylesheet = newStylesheet(source, 0, null);
return new TemplatesImpl(this, stylesheet);
}
Stylesheet newStylesheet(Source source, int precedence, Stylesheet parent)
throws TransformerConfigurationException
{
Document doc = null;
String systemId = null;
if (source != null)
{
try
{
DOMSource ds;
synchronized (resolver)
{
resolver.setUserResolver(userResolver);
resolver.setUserListener(userListener);
ds = resolver.resolveDOM(source, null, null);
}
Node node = ds.getNode();
if (node == null)
{
throw new TransformerConfigurationException("no source document");
}
doc = (node instanceof Document) ? (Document) node :
node.getOwnerDocument();
systemId = ds.getSystemId();
}
catch (TransformerException e)
{
throw new TransformerConfigurationException(e);
}
}
return new Stylesheet(this, parent, doc, systemId, precedence);
}
public Source getAssociatedStylesheet(Source source,
String media,
String title,
String charset)
throws TransformerConfigurationException
{
try
{
DOMSource ds;
synchronized (resolver)
{
resolver.setUserResolver(userResolver);
resolver.setUserListener(userListener);
ds = resolver.resolveDOM(source, null, null);
}
Node node = ds.getNode();
if (node == null)
{
throw new TransformerConfigurationException("no source document");
}
Document doc = (node instanceof Document) ? (Document) node :
node.getOwnerDocument();
LinkedList matches = new LinkedList();
for (node = doc.getFirstChild();
node != null;
node = node.getNextSibling())
{
if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE &&
"xml-stylesheet".equals(node.getNodeName()))
{
Map params = parseParameters(node.getNodeValue());
if (media != null && !media.equals(params.get("media")))
{
continue;
}
if (title != null && !title.equals(params.get("title")))
{
continue;
}
if (charset != null && !charset.equals(params.get("charset")))
{
continue;
}
String href = (String) params.get("href");
URL url = resolver.resolveURL(null, node.getBaseURI(), href);
matches.add(url);
}
}
switch (matches.size())
{
case 0:
return null;
case 1:
return new StreamSource(((URL) matches.getFirst()).toString());
default:
// Create a source representing a stylesheet with a list of
// imports
DomDocument ssDoc = new DomDocument();
ssDoc.setBuilding(true);
// Create document element
Node root =
ssDoc.createElementNS(Stylesheet.XSL_NS, "stylesheet");
Node version =
ssDoc.createAttributeNS(null, "version");
version.setNodeValue("1.0");
root.getAttributes().setNamedItemNS(version);
ssDoc.appendChild(root);
// Create xsl:import for each URL
for (Iterator i = matches.iterator(); i.hasNext(); )
{
URL url = (URL) i.next();
Node imp =
ssDoc.createElementNS(Stylesheet.XSL_NS, "import");
Node href =
ssDoc.createAttributeNS(null, "href");
href.setNodeValue(url.toString());
imp.getAttributes().setNamedItemNS(href);
root.appendChild(imp);
}
ssDoc.setBuilding(false);
return new DOMSource(ssDoc);
}
}
catch (IOException e)
{
throw new TransformerConfigurationException(e);
}
catch (TransformerException e)
{
throw new TransformerConfigurationException(e);
}
}
Map parseParameters(String data)
{
Map ret = new LinkedHashMap();
int len = data.length();
String key = null;
int start = 0;
char quoteChar = '\u0000';
for (int i = 0; i < len; i++)
{
char c = data.charAt(i);
if (quoteChar == '\u0000' && c == ' ')
{
if (key == null && start < i)
{
key = data.substring(start, i);
}
else
{
String val = unquote(data.substring(start, i).trim());
ret.put(key, val);
key = null;
}
start = i + 1;
}
else if (c == '"')
{
quoteChar = (quoteChar == c) ? '\u0000' : c;
}
else if (c == '\'')
{
quoteChar = (quoteChar == c) ? '\u0000' : c;
}
}
if (start < len && key != null)
{
String val = unquote(data.substring(start, len).trim());
ret.put(key, val);
}
return ret;
}
String unquote(String text)
{
int end = text.length() - 1;
if (text.charAt(0) == '\'' && text.charAt(end) == '\'')
{
return text.substring(1, end);
}
if (text.charAt(0) == '"' && text.charAt(end) == '"')
{
return text.substring(1, end);
}
return text;
}
public void setURIResolver(URIResolver resolver)
{
userResolver = resolver;
}
public URIResolver getURIResolver()
{
return userResolver;
}
public void setFeature(String name, boolean value)
throws TransformerConfigurationException
{
throw new TransformerConfigurationException("not supported");
}
public boolean getFeature(String name)
{
if (SAXSource.FEATURE.equals(name) ||
SAXResult.FEATURE.equals(name) ||
StreamSource.FEATURE.equals(name) ||
StreamResult.FEATURE.equals(name) ||
DOMSource.FEATURE.equals(name) ||
DOMResult.FEATURE.equals(name))
{
return true;
}
return false;
}
public void setAttribute(String name, Object value)
throws IllegalArgumentException
{
throw new IllegalArgumentException("not supported");
}
public Object getAttribute(String name)
throws IllegalArgumentException
{
throw new IllegalArgumentException("not supported");
}
public void setErrorListener(ErrorListener listener)
throws IllegalArgumentException
{
userListener = listener;
}
public ErrorListener getErrorListener()
{
return userListener;
}
}
@@ -0,0 +1,769 @@
/* TransformerImpl.java --
Copyright (C) 2004 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 java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.UnknownServiceException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import javax.xml.namespace.QName;
import javax.xml.transform.ErrorListener;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.URIResolver;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.ext.LexicalHandler;
import gnu.xml.dom.DomDoctype;
import gnu.xml.dom.DomDocument;
import gnu.xml.dom.ls.WriterOutputStream;
/**
* The transformation process for a given stylesheet.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
class TransformerImpl
extends Transformer
{
final TransformerFactoryImpl factory;
final Stylesheet stylesheet;
URIResolver uriResolver;
ErrorListener errorListener;
Properties outputProperties;
TransformerImpl(TransformerFactoryImpl factory,
Stylesheet stylesheet,
Properties outputProperties)
throws TransformerConfigurationException
{
this.factory = factory;
uriResolver = factory.userResolver;
errorListener = factory.userListener;
this.stylesheet = stylesheet;
this.outputProperties = outputProperties;
if (stylesheet != null)
{
// Set up parameter context for this transformer
stylesheet.bindings.push(Bindings.PARAM);
}
}
public void transform(Source xmlSource, Result outputTarget)
throws TransformerException
{
// Get the source tree
DOMSource source;
synchronized (factory.resolver)
{
factory.resolver.setUserResolver(uriResolver);
factory.resolver.setUserListener(errorListener);
source = factory.resolver.resolveDOM(xmlSource, null, null);
}
Node context = source.getNode();
Document doc = (context instanceof Document) ? (Document) context :
context.getOwnerDocument();
if (doc instanceof DomDocument)
{
// Suppress mutation events
((DomDocument) doc).setBuilding(true);
// TODO find a better/more generic way of doing this than
// casting
}
// Get the result tree
Node parent = null, nextSibling = null;
if (outputTarget instanceof DOMResult)
{
DOMResult dr = (DOMResult) outputTarget;
parent = dr.getNode();
nextSibling = dr.getNextSibling();
Document rdoc = (parent instanceof Document) ? (Document) parent :
parent.getOwnerDocument();
if (rdoc instanceof DomDocument)
{
// Suppress mutation events and allow multiple root elements
DomDocument drdoc = (DomDocument) rdoc;
drdoc.setBuilding(true);
drdoc.setCheckWellformedness(false);
// TODO find a better/more generic way of doing this than
// casting
}
}
boolean created = false;
// Transformation
if (stylesheet != null)
{
if (parent == null)
{
// Create a new document to hold the result
DomDocument resultDoc = new DomDocument();
resultDoc.setBuilding(true);
resultDoc.setCheckWellformedness(false);
parent = resultDoc;
created = true;
}
// Make a copy of the source node, and strip it
context = context.cloneNode(true);
strip(context);
// XSLT transformation
try
{
// Set output properties in the underlying stylesheet
((TransformerOutputProperties) outputProperties).apply();
stylesheet.initTopLevelVariables(context);
TemplateNode t = stylesheet.getTemplate(null, context, false);
if (t != null)
{
stylesheet.current = context;
t.apply(stylesheet, null, context, 1, 1, parent, nextSibling);
}
}
catch (TransformerException e)
{
// Done transforming, reset document
if (doc instanceof DomDocument)
{
((DomDocument) doc).setBuilding(false);
}
throw e;
}
}
else
{
// Identity transform
Node clone = context.cloneNode(true);
if (context.getNodeType() != Node.DOCUMENT_NODE)
{
Document resultDoc;
if (parent == null)
{
// Create a new document to hold the result
DomDocument rd = new DomDocument();
rd.setBuilding(true);
rd.setCheckWellformedness(false);
parent = resultDoc = rd;
created = true;
}
else
{
resultDoc = (parent instanceof Document) ?
(Document) parent :
parent.getOwnerDocument();
}
Document sourceDoc = context.getOwnerDocument();
if (sourceDoc != resultDoc)
{
clone = resultDoc.adoptNode(clone);
}
if (nextSibling != null)
{
parent.insertBefore(clone, nextSibling);
}
else
{
parent.appendChild(clone);
}
}
else
{
// Cannot append document to another tree
parent = clone;
created = true;
}
}
String method = outputProperties.getProperty(OutputKeys.METHOD);
int outputMethod = "html".equals(method) ? Stylesheet.OUTPUT_HTML :
"text".equals(method) ? Stylesheet.OUTPUT_TEXT :
Stylesheet.OUTPUT_XML;
String encoding = outputProperties.getProperty(OutputKeys.ENCODING);
String publicId = outputProperties.getProperty(OutputKeys.DOCTYPE_PUBLIC);
String systemId = outputProperties.getProperty(OutputKeys.DOCTYPE_SYSTEM);
String version = outputProperties.getProperty(OutputKeys.VERSION);
boolean omitXmlDeclaration =
"yes".equals(outputProperties.getProperty(OutputKeys.OMIT_XML_DECLARATION));
boolean standalone =
"yes".equals(outputProperties.getProperty(OutputKeys.STANDALONE));
String mediaType = outputProperties.getProperty(OutputKeys.MEDIA_TYPE);
String cdataSectionElements =
outputProperties.getProperty(OutputKeys.CDATA_SECTION_ELEMENTS);
boolean indent =
"yes".equals(outputProperties.getProperty(OutputKeys.INDENT));
if (created)
{
// Discover document element
DomDocument resultDoc = (DomDocument) parent;
Node root = resultDoc.getDocumentElement();
// Add doctype if specified
if ((publicId != null || systemId != null) &&
root != null)
{
// We must know the name of the root element to
// create the document type
resultDoc.appendChild(new DomDoctype(resultDoc,
root.getNodeName(),
publicId,
systemId));
}
resultDoc.setBuilding(false);
resultDoc.setCheckWellformedness(true);
}
else if (publicId != null || systemId != null)
{
switch (parent.getNodeType())
{
case Node.DOCUMENT_NODE:
case Node.DOCUMENT_FRAGMENT_NODE:
Document resultDoc = (parent instanceof Document) ?
(Document) parent :
parent.getOwnerDocument();
DOMImplementation impl = resultDoc.getImplementation();
DocumentType doctype =
impl.createDocumentType(resultDoc.getNodeName(),
publicId,
systemId);
// Try to insert doctype before first element
Node ctx = parent.getFirstChild();
for (; ctx != null &&
ctx.getNodeType() != Node.ELEMENT_NODE;
ctx = ctx.getNextSibling())
{
}
if (ctx != null)
{
parent.insertBefore(doctype, ctx);
}
else
{
parent.appendChild(doctype);
}
}
}
if (version != null)
{
parent.setUserData("version", version, stylesheet);
}
if (omitXmlDeclaration)
{
parent.setUserData("omit-xml-declaration", "yes", stylesheet);
}
if (standalone)
{
parent.setUserData("standalone", "yes", stylesheet);
}
if (mediaType != null)
{
parent.setUserData("media-type", mediaType, stylesheet);
}
if (cdataSectionElements != null)
{
List list = new LinkedList();
StringTokenizer st = new StringTokenizer(cdataSectionElements);
while (st.hasMoreTokens())
{
String name = st.nextToken();
String localName = name;
String uri = null;
String prefix = null;
int ci = name.indexOf(':');
if (ci != -1)
{
// Use namespaces defined on xsl:output node to resolve
// namespaces for QName
prefix = name.substring(0, ci);
localName = name.substring(ci + 1);
uri = stylesheet.output.lookupNamespaceURI(prefix);
}
list.add(new QName(uri, localName, prefix));
}
if (!list.isEmpty())
{
Document resultDoc = (parent instanceof Document) ?
(Document) parent :
parent.getOwnerDocument();
convertCdataSectionElements(resultDoc, parent, list);
}
}
if (indent)
{
parent.normalize();
strip(parent);
Document resultDoc = (parent instanceof Document) ?
(Document) parent :
parent.getOwnerDocument();
reindent(resultDoc, parent, 0);
}
// Render result to the target device
if (outputTarget instanceof DOMResult)
{
if (created)
{
DOMResult dr = (DOMResult) outputTarget;
dr.setNode(parent);
dr.setNextSibling(null);
}
}
else if (outputTarget instanceof StreamResult)
{
StreamResult sr = (StreamResult) outputTarget;
IOException ex = null;
try
{
writeStreamResult(parent, sr, outputMethod, encoding);
}
catch (UnsupportedEncodingException e)
{
try
{
writeStreamResult(parent, sr, outputMethod, "UTF-8");
}
catch (IOException e2)
{
ex = e2;
}
}
catch (IOException e)
{
ex = e;
}
if (ex != null)
{
if (errorListener != null)
{
errorListener.error(new TransformerException(ex));
}
else
{
ex.printStackTrace(System.err);
}
}
}
else if (outputTarget instanceof SAXResult)
{
SAXResult sr = (SAXResult) outputTarget;
try
{
ContentHandler ch = sr.getHandler();
LexicalHandler lh = sr.getLexicalHandler();
if (lh == null && ch instanceof LexicalHandler)
{
lh = (LexicalHandler) ch;
}
SAXSerializer serializer = new SAXSerializer();
serializer.serialize(parent, ch, lh);
}
catch (SAXException e)
{
if (errorListener != null)
{
errorListener.error(new TransformerException(e));
}
else
{
e.printStackTrace(System.err);
}
}
}
}
/**
* Strip whitespace from the source tree.
*/
void strip(Node node)
throws TransformerConfigurationException
{
short nt = node.getNodeType();
if (nt == Node.ENTITY_REFERENCE_NODE)
{
// Replace entity reference with its content
Node parent = node.getParentNode();
Node child = node.getFirstChild();
if (child != null)
{
strip(child);
}
while (child != null)
{
Node next = child.getNextSibling();
node.removeChild(child);
parent.insertBefore(child, node);
child = next;
}
parent.removeChild(node);
}
if (nt == Node.TEXT_NODE || nt == Node.CDATA_SECTION_NODE)
{
if (!stylesheet.isPreserved((Text) node))
{
node.getParentNode().removeChild(node);
}
else
{
String text = node.getNodeValue();
String stripped = text.trim();
if (!text.equals(stripped))
{
node.setNodeValue(stripped);
}
}
}
else
{
for (Node child = node.getFirstChild(); child != null;
child = child.getNextSibling())
{
strip(child);
}
}
}
/**
* Obtain a suitable output stream for writing the result to,
* and use the StreamSerializer to write the result tree to the stream.
*/
void writeStreamResult(Node node, StreamResult sr, int outputMethod,
String encoding)
throws IOException
{
OutputStream out = null;
try
{
out = sr.getOutputStream();
if (out == null)
{
Writer writer = sr.getWriter();
if (writer != null)
{
out = new WriterOutputStream(writer);
}
}
if (out == null)
{
String systemId = sr.getSystemId();
try
{
URL url = new URL(systemId);
URLConnection connection = url.openConnection();
connection.setDoOutput(true);
out = connection.getOutputStream();
}
catch (MalformedURLException e)
{
out = new FileOutputStream(systemId);
}
catch (UnknownServiceException e)
{
URL url = new URL(systemId);
out = new FileOutputStream(url.getPath());
}
}
out = new BufferedOutputStream(out);
StreamSerializer serializer =
new StreamSerializer(outputMethod, encoding, null);
if (stylesheet != null)
{
Collection celem = stylesheet.outputCdataSectionElements;
serializer.setCdataSectionElements(celem);
}
serializer.serialize(node, out);
out.flush();
}
finally
{
try
{
if (out != null)
{
out.close();
}
}
catch (IOException e)
{
}
}
}
void copyChildren(Document dstDoc, Node src, Node dst)
{
Node srcChild = src.getFirstChild();
while (srcChild != null)
{
Node dstChild = dstDoc.adoptNode(srcChild);
dst.appendChild(dstChild);
srcChild = srcChild.getNextSibling();
}
}
public void setParameter(String name, Object value)
{
if (stylesheet != null)
{
stylesheet.bindings.set(new QName(null, name), value, Bindings.PARAM);
}
}
public Object getParameter(String name)
{
if (stylesheet != null)
{
return stylesheet.bindings.get(new QName(null, name), null, 1, 1);
}
return null;
}
public void clearParameters()
{
if (stylesheet != null)
{
stylesheet.bindings.pop(Bindings.PARAM);
stylesheet.bindings.push(Bindings.PARAM);
}
}
public void setURIResolver(URIResolver resolver)
{
uriResolver = resolver;
}
public URIResolver getURIResolver()
{
return uriResolver;
}
public void setOutputProperties(Properties oformat)
throws IllegalArgumentException
{
if (oformat == null)
{
outputProperties.clear();
}
else
{
outputProperties.putAll(oformat);
}
}
public Properties getOutputProperties()
{
return (Properties) outputProperties.clone();
}
public void setOutputProperty(String name, String value)
throws IllegalArgumentException
{
outputProperties.put(name, value);
}
public String getOutputProperty(String name)
throws IllegalArgumentException
{
return outputProperties.getProperty(name);
}
public void setErrorListener(ErrorListener listener)
{
errorListener = listener;
}
public ErrorListener getErrorListener()
{
return errorListener;
}
static final String INDENT_WHITESPACE = " ";
/*
* Apply indent formatting to the given tree.
*/
void reindent(Document doc, Node node, int offset)
{
if (node.hasChildNodes())
{
boolean markupContent = false;
boolean textContent = false;
List children = new LinkedList();
Node ctx = node.getFirstChild();
while (ctx != null)
{
switch (ctx.getNodeType())
{
case Node.ELEMENT_NODE:
case Node.PROCESSING_INSTRUCTION_NODE:
case Node.DOCUMENT_TYPE_NODE:
markupContent = true;
break;
case Node.TEXT_NODE:
case Node.CDATA_SECTION_NODE:
case Node.ENTITY_REFERENCE_NODE:
case Node.COMMENT_NODE:
textContent = true;
break;
}
children.add(ctx);
ctx = ctx.getNextSibling();
}
if (markupContent)
{
if (textContent)
{
// XXX handle mixed content differently?
}
int nodeType = node.getNodeType();
if (nodeType == Node.DOCUMENT_NODE)
{
for (Iterator i = children.iterator(); i.hasNext(); )
{
ctx = (Node) i.next();
reindent(doc, ctx, offset + 1);
}
}
else
{
StringBuffer buf = new StringBuffer();
buf.append('\n');
for (int i = 0; i < offset + 1; i++)
{
buf.append(INDENT_WHITESPACE);
}
String ws = buf.toString();
for (Iterator i = children.iterator(); i.hasNext(); )
{
ctx = (Node) i.next();
node.insertBefore(doc.createTextNode(ws), ctx);
reindent(doc, ctx, offset + 1);
}
buf = new StringBuffer();
buf.append('\n');
ws = buf.toString();
for (int i = 0; i < offset; i++)
{
buf.append(INDENT_WHITESPACE);
}
node.appendChild(doc.createTextNode(ws));
}
}
}
}
/**
* Converts the text node children of any cdata-section-elements in the
* tree to CDATA section nodes.
*/
void convertCdataSectionElements(Document doc, Node node, List list)
{
if (node.getNodeType() == Node.ELEMENT_NODE)
{
boolean match = false;
for (Iterator i = list.iterator(); i.hasNext(); )
{
QName qname = (QName) i.next();
if (match(qname, node))
{
match = true;
break;
}
}
if (match)
{
Node ctx = node.getFirstChild();
while (ctx != null)
{
if (ctx.getNodeType() == Node.TEXT_NODE)
{
Node cdata = doc.createCDATASection(ctx.getNodeValue());
node.replaceChild(cdata, ctx);
ctx = cdata;
}
ctx = ctx.getNextSibling();
}
}
}
Node ctx = node.getFirstChild();
while (ctx != null)
{
if (ctx.hasChildNodes())
{
convertCdataSectionElements(doc, ctx, list);
}
ctx = ctx.getNextSibling();
}
}
boolean match(QName qname, Node node)
{
String ln1 = qname.getLocalPart();
String ln2 = node.getLocalName();
if (ln2 == null)
{
return ln1.equals(node.getNodeName());
}
else
{
String uri1 = qname.getNamespaceURI();
String uri2 = node.getNamespaceURI();
return (uri1.equals(uri2) && ln1.equals(ln2));
}
}
}
@@ -0,0 +1,185 @@
/* TransformerOutputProperties.java --
Copyright (C) 2004 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 java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Properties;
import java.util.StringTokenizer;
import javax.xml.transform.OutputKeys;
/**
* Helper class to manage JAXP user setting of output properties.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
class TransformerOutputProperties
extends Properties
{
final Properties defaultProperties;
final Stylesheet stylesheet;
boolean dirty;
TransformerOutputProperties(Stylesheet stylesheet)
{
this.stylesheet = stylesheet;
defaultProperties = new Properties();
switch (stylesheet.outputMethod)
{
case Stylesheet.OUTPUT_XML:
defaultProperties.put(OutputKeys.METHOD, "xml");
break;
case Stylesheet.OUTPUT_HTML:
defaultProperties.put(OutputKeys.METHOD, "html");
break;
case Stylesheet.OUTPUT_TEXT:
defaultProperties.put(OutputKeys.METHOD, "text");
break;
}
if (stylesheet.outputVersion != null)
{
defaultProperties.put(OutputKeys.VERSION, stylesheet.outputVersion);
}
if (stylesheet.outputEncoding != null)
{
defaultProperties.put(OutputKeys.ENCODING, stylesheet.outputEncoding);
}
defaultProperties.put(OutputKeys.OMIT_XML_DECLARATION,
stylesheet.outputOmitXmlDeclaration ? "yes" : "no");
defaultProperties.put(OutputKeys.STANDALONE,
stylesheet.outputStandalone ? "yes" : "no");
if (stylesheet.outputPublicId != null)
{
defaultProperties.put(OutputKeys.DOCTYPE_PUBLIC,
stylesheet.outputPublicId);
}
if (stylesheet.outputSystemId != null)
{
defaultProperties.put(OutputKeys.DOCTYPE_SYSTEM,
stylesheet.outputSystemId);
}
StringBuffer buf = new StringBuffer();
for (Iterator i = stylesheet.outputCdataSectionElements.iterator();
i.hasNext(); )
{
if (buf.length() > 0)
{
buf.append(' ');
}
buf.append((String) i.next());
}
defaultProperties.put(OutputKeys.CDATA_SECTION_ELEMENTS, buf.toString());
defaultProperties.put(OutputKeys.INDENT,
stylesheet.outputIndent ? "yes" : "no");
if (stylesheet.outputMediaType != null)
{
defaultProperties.put(OutputKeys.MEDIA_TYPE,
stylesheet.outputMediaType);
}
}
public String getProperty(String key)
{
String val = super.getProperty(key);
if (val == null)
{
val = defaultProperties.getProperty(key);
}
return val;
}
public Object put(Object key, Object value)
{
Object ret = super.put(key, value);
dirty = true;
return ret;
}
public void clear()
{
super.clear();
dirty = true;
}
/**
* Applies the current set of properties to the underlying stylesheet.
*/
void apply()
{
if (!dirty)
{
return;
}
String method = getProperty(OutputKeys.METHOD);
if ("xml".equals(method))
{
stylesheet.outputMethod = Stylesheet.OUTPUT_XML;
}
else if ("html".equals(method))
{
stylesheet.outputMethod = Stylesheet.OUTPUT_HTML;
}
else if ("text".equals(method))
{
stylesheet.outputMethod = Stylesheet.OUTPUT_TEXT;
}
stylesheet.outputVersion = getProperty(OutputKeys.VERSION);
stylesheet.outputEncoding = getProperty(OutputKeys.ENCODING);
stylesheet.outputOmitXmlDeclaration =
"yes".equals(getProperty(OutputKeys.OMIT_XML_DECLARATION));
stylesheet.outputStandalone =
"yes".equals(getProperty(OutputKeys.STANDALONE));
stylesheet.outputPublicId = getProperty(OutputKeys.DOCTYPE_PUBLIC);
stylesheet.outputSystemId = getProperty(OutputKeys.DOCTYPE_SYSTEM);
StringTokenizer st =
new StringTokenizer(getProperty(OutputKeys.CDATA_SECTION_ELEMENTS));
Collection acc = new LinkedHashSet();
while (st.hasMoreTokens())
{
acc.add(st.nextToken());
}
stylesheet.outputCdataSectionElements = acc;
stylesheet.outputIndent = "yes".equals(getProperty(OutputKeys.INDENT));
stylesheet.outputMediaType = getProperty(OutputKeys.MEDIA_TYPE);
dirty = false;
}
}
@@ -0,0 +1,83 @@
/* URIResolverEntityResolver.java --
Copyright (C) 2004 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 java.io.IOException;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.URIResolver;
import javax.xml.transform.sax.SAXSource;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* EntityResolver that wraps a URIResolver.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
class URIResolverEntityResolver
implements EntityResolver
{
final URIResolver resolver;
URIResolverEntityResolver(URIResolver resolver)
{
this.resolver = resolver;
}
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException
{
try
{
Source source = resolver.resolve(null, systemId);
if (source == null)
{
return null;
}
return SAXSource.sourceToInputSource(source);
}
catch (TransformerException e)
{
throw new SAXException(e);
}
}
}
@@ -0,0 +1,132 @@
/* UnparsedEntityUriFunction.java --
Copyright (C) 2004 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 java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.xpath.XPathFunction;
import javax.xml.xpath.XPathFunctionException;
import org.w3c.dom.DocumentType;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.Notation;
import gnu.xml.xpath.Expr;
import gnu.xml.xpath.Function;
/**
* The XSLT <code>unparsed-entity-uri()</code>function.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class UnparsedEntityUriFunction
extends Expr
implements XPathFunction, Function
{
List args;
public Object evaluate(List args)
throws XPathFunctionException
{
// Useless...
return Collections.EMPTY_SET;
}
public void setArguments(List args)
{
this.args = args;
}
public Object evaluate(Node context, int pos, int len)
{
int arity = args.size();
List values = new ArrayList(arity);
for (int i = 0; i < arity; i++)
{
Expr arg = (Expr) args.get(i);
values.add(arg.evaluate(context, pos, len));
}
String name = _string(context, values.get(0));
DocumentType doctype = context.getOwnerDocument().getDoctype();
if (doctype != null)
{
NamedNodeMap notations = doctype.getNotations();
Notation notation = (Notation) notations.getNamedItem(name);
if (notation != null)
{
String systemId = notation.getSystemId();
// XXX absolutize?
if (systemId != null)
{
return systemId;
}
}
}
return "";
}
public Expr clone(Object context)
{
UnparsedEntityUriFunction f = new UnparsedEntityUriFunction();
int len = args.size();
List args2 = new ArrayList(len);
for (int i = 0; i < len; i++)
{
args2.add(((Expr) args.get(i)).clone(context));
}
f.setArguments(args2);
return f;
}
public boolean references(QName var)
{
for (Iterator i = args.iterator(); i.hasNext(); )
{
if (((Expr) i.next()).references(var))
{
return true;
}
}
return false;
}
}
@@ -0,0 +1,161 @@
/* ValueOfNode.java --
Copyright (C) 2004 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 java.util.Collection;
import java.util.Iterator;
import javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
import gnu.xml.xpath.Expr;
/**
* A template node representing an XSLT <code>value-of</code> instruction.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class ValueOfNode
extends TemplateNode
{
final Expr select;
final boolean disableOutputEscaping;
ValueOfNode(Expr select, boolean disableOutputEscaping)
{
this.select = select;
this.disableOutputEscaping = disableOutputEscaping;
}
TemplateNode clone(Stylesheet stylesheet)
{
TemplateNode ret = new ValueOfNode(select.clone(stylesheet),
disableOutputEscaping);
if (children != null)
{
ret.children = children.clone(stylesheet);
}
if (next != null)
{
ret.next = next.clone(stylesheet);
}
return ret;
}
void doApply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
Object ret = select.evaluate(context, pos, len);
/*if (stylesheet.debug)
{
System.err.println("value-of: " + select + " -> " + ret);
}*/
String value;
if (ret instanceof Collection)
{
StringBuffer buf = new StringBuffer();
for (Iterator i = ((Collection) ret).iterator(); i.hasNext(); )
{
Node node = (Node) i.next();
buf.append(Expr.stringValue(node));
}
value = buf.toString();
}
else
{
value = Expr._string(context, ret);
}
if (stylesheet.debug)
{
System.err.println("value-of: "+context+" "+ select + " -> "+ value);
}
if (value != null && value.length() > 0)
{
Document doc = (parent instanceof Document) ?
(Document) parent : parent.getOwnerDocument();
Text textNode = doc.createTextNode(value);
if (disableOutputEscaping)
{
textNode.setUserData("disable-output-escaping", "yes", stylesheet);
}
if (nextSibling != null)
{
parent.insertBefore(textNode, nextSibling);
}
else
{
parent.appendChild(textNode);
}
}
// value-of doesn't process children
if (next != null)
{
next.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
}
public boolean references(QName var)
{
if (select != null && select.references(var))
{
return true;
}
return super.references(var);
}
public String toString()
{
StringBuffer buf = new StringBuffer(getClass().getName());
buf.append('[');
buf.append("select=");
buf.append(select);
if (disableOutputEscaping)
{
buf.append(",disableOutputEscaping");
}
buf.append(']');
return buf.toString();
}
}
@@ -0,0 +1,123 @@
/* WhenNode.java --
Copyright (C) 2004 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 javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
/**
* A template node representing an XSL <code>when</code> instruction.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class WhenNode
extends TemplateNode
{
final Expr test;
WhenNode(Expr test)
{
this.test = test;
}
TemplateNode clone(Stylesheet stylesheet)
{
TemplateNode ret = new WhenNode(test.clone(stylesheet));
if (children != null)
{
ret.children = children.clone(stylesheet);
}
if (next != null)
{
ret.next = next.clone(stylesheet);
}
return ret;
}
void doApply(Stylesheet stylesheet, QName mode,
Node context, int pos, int len,
Node parent, Node nextSibling)
throws TransformerException
{
Object ret = test.evaluate(context, pos, len);
boolean success = (ret instanceof Boolean) ?
((Boolean) ret).booleanValue() :
Expr._boolean(context, ret);
if (success)
{
if (children != null)
{
children.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
}
else
{
if (next != null)
{
next.apply(stylesheet, mode,
context, pos, len,
parent, nextSibling);
}
}
}
public boolean references(QName var)
{
if (test != null && test.references(var))
{
return true;
}
return super.references(var);
}
public String toString()
{
StringBuffer buf = new StringBuffer(getClass().getName());
buf.append('[');
buf.append("test=");
buf.append(test);
buf.append(']');
return buf.toString();
}
}
@@ -0,0 +1,123 @@
/* WithParam.java --
Copyright (C) 2004 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 java.util.Collections;
import javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
/**
* A specification for setting a variable or parameter during template
* processing with <code>apply-templates</code> or
* <code>call-template</code>.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
final class WithParam
{
final QName name;
final Expr select;
final TemplateNode content;
WithParam(QName name, Expr select)
{
this.name = name;
this.select = select;
content = null;
}
WithParam(QName name, TemplateNode content)
{
this.name = name;
this.content = content;
select = null;
}
Object getValue(Stylesheet stylesheet, QName mode,
Node context, int pos, int len)
throws TransformerException
{
if (select != null)
{
return select.evaluate(context, pos, len);
}
else
{
Document doc = (context instanceof Document) ? (Document) context :
context.getOwnerDocument();
DocumentFragment fragment = doc.createDocumentFragment();
content.apply(stylesheet, mode,
context, pos, len,
fragment, null);
return Collections.singleton(fragment);
}
}
WithParam clone(Stylesheet stylesheet)
{
if (content == null)
{
return new WithParam(name,
select.clone(stylesheet));
}
else
{
return new WithParam(name,
content.clone(stylesheet));
}
}
boolean references(QName var)
{
if (select != null && select.references(var))
{
return true;
}
if (content != null && content.references(var))
{
return true;
}
return false;
}
}
@@ -0,0 +1,124 @@
/* XSLComparator.java --
Copyright (C) 2004 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 java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.text.Collator;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
/**
* Comparator for sorting lists of nodes according to a list of sort keys.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
class XSLComparator
implements Comparator
{
final List sortKeys;
XSLComparator(List sortKeys)
{
this.sortKeys = sortKeys;
}
public int compare(Object o1, Object o2)
{
if (o1 instanceof Node && o2 instanceof Node)
{
Node n1 = (Node) o1;
Node n2 = (Node) o2;
for (Iterator i = sortKeys.iterator(); i.hasNext(); )
{
SortKey sortKey = (SortKey) i.next();
String k1 = sortKey.key(n1);
String k2 = sortKey.key(n2);
if ("text".equals(sortKey.dataType))
{
Locale locale = (sortKey.lang == null) ? Locale.getDefault() :
new Locale(sortKey.lang);
Collator collator = Collator.getInstance(locale);
int d = collator.compare(k1, k2);
if (d != 0)
{
switch (sortKey.caseOrder)
{
case SortKey.UPPER_FIRST:
// TODO
break;
case SortKey.LOWER_FIRST:
// TODO
break;
}
if (sortKey.descending)
{
d = -d;
}
return d;
}
}
else if ("number".equals(sortKey.dataType))
{
double kn1 = Expr._number(n1, k1);
double kn2 = Expr._number(n2, k2);
int d;
if (Double.isNaN(kn1) || Double.isInfinite(kn2))
{
d = -1;
}
else if (Double.isNaN(kn2) || Double.isInfinite(kn1))
{
d = 1;
}
else
{
// conversion to int may give 0 for small numbers
d = (kn1 > kn2) ? 1 : (kn1 < kn2) ? -1 : 0;
}
return (sortKey.descending) ? -d : d;
}
}
}
return 0;
}
}
@@ -0,0 +1,282 @@
/* XSLURIResolver.java --
Copyright (C) 2004 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 java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.ErrorListener;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.URIResolver;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import gnu.xml.dom.ls.ReaderInputStream;
/**
* URI resolver for XSLT.
* This resolver parses external entities into DOMSources. It
* maintains a cache of URIs to DOMSources to avoid expensive re-parsing.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
class XSLURIResolver
implements URIResolver
{
Map lastModifiedCache = new HashMap();
Map nodeCache = new HashMap();
DocumentBuilder builder;
URIResolver userResolver;
ErrorListener userListener;
void setUserResolver(URIResolver userResolver)
{
this.userResolver = userResolver;
}
void setUserListener(ErrorListener userListener)
{
this.userListener = userListener;
}
/**
* Clear the cache.
*/
void flush()
{
lastModifiedCache.clear();
nodeCache.clear();
}
public Source resolve(String href, String base)
throws TransformerException
{
Source source = null;
if (userResolver != null)
{
source = userResolver.resolve(base, href);
}
return resolveDOM(source, href, base);
}
DOMSource resolveDOM(Source source, String base, String href)
throws TransformerException
{
if (source != null && source instanceof DOMSource)
{
return (DOMSource) source;
}
String systemId = (source == null) ? null : source.getSystemId();
long lastModified = 0L, lastLastModified = 0L;
try
{
URL url = resolveURL(systemId, base, href);
Node node = null;
InputStream in = null;
if (source instanceof StreamSource)
{
StreamSource ss = (StreamSource) source;
in = ss.getInputStream();
if (in == null)
{
Reader reader = ss.getReader();
if (reader != null)
{
in = new ReaderInputStream(reader);
}
}
}
if (in == null)
{
if (url != null)
{
systemId = url.toString();
node = (Node) nodeCache.get(systemId);
// Is the resource up to date?
URLConnection conn = url.openConnection();
Long llm = (Long) lastModifiedCache.get(systemId);
if (llm != null)
{
lastLastModified = llm.longValue();
conn.setIfModifiedSince(lastLastModified);
}
conn.connect();
lastModified = conn.getLastModified();
if (node != null &&
lastModified > 0L &&
lastModified <= lastLastModified)
{
// Resource unchanged
return new DOMSource(node, systemId);
}
else
{
// Resource new or modified
in = conn.getInputStream();
nodeCache.put(systemId, node);
lastModifiedCache.put(systemId, new Long(lastModified));
}
}
else
{
throw new TransformerException("can't resolve URL: " +
systemId);
}
}
InputSource input = new InputSource(in);
input.setSystemId(systemId);
DocumentBuilder builder = getDocumentBuilder();
node = builder.parse(input);
return new DOMSource(node, systemId);
}
catch (IOException e)
{
throw new TransformerException(e);
}
catch (SAXException e)
{
throw new TransformerException(e);
}
}
URL resolveURL(String systemId, String base, String href)
throws IOException
{
URL url = null;
try
{
if (systemId != null)
{
try
{
url = new URL(systemId);
}
catch (MalformedURLException e)
{
// Try building from base + href
}
}
if (url == null)
{
if (base != null)
{
URL baseURL = new URL(base);
url = new URL(baseURL, href);
}
else if (href != null)
{
url = new URL(href);
}
else
{
// See below
throw new MalformedURLException(systemId);
}
}
return url;
}
catch (MalformedURLException e)
{
// Fall back to local filesystem
File file = null;
if (href == null)
{
href = systemId;
}
if (base != null)
{
int lsi = base.lastIndexOf(File.separatorChar);
if (lsi != -1 && lsi < base.length() - 1)
{
base = base.substring(0, lsi);
}
File baseFile = new File(base);
file = new File(baseFile, href);
}
else if (href != null)
{
file = new File(href);
}
return (file == null) ? null : file.toURL();
}
}
DocumentBuilder getDocumentBuilder()
throws TransformerException
{
try
{
if (builder == null)
{
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setExpandEntityReferences(true);
builder = factory.newDocumentBuilder();
}
if (userResolver != null)
{
builder.setEntityResolver(new URIResolverEntityResolver(userResolver));
}
if (userListener != null)
{
builder.setErrorHandler(new ErrorListenerErrorHandler(userListener));
}
return builder;
}
catch (Exception e)
{
throw new TransformerException(e);
}
}
}
@@ -0,0 +1,77 @@
<html>
<body>
<h1>GNU JAXP XSL transformer</h1>
<div>
This package contains a Java XSL transformer compliant with the JAXP
specification. It depends on the GNU DOM and XPath implementations, and
will generate GNU DOM nodes unless a specific target from another
implementation was given. It understands DOM, SAX, and stream sources
and result sinks and supports these JAXP features.
</div>
<div>
To use this transformer, set the system property
<code>javax.xml.transform.TransformerFactory</code> to the value
<code>gnu.xml.transform.TransformerFactoryImpl</code>. You can then
instantiate <a href='TransformerFactory.html'>TransformerFactory</a>
and transformers in the ordinary manner. Reuse of stylesheets is
supported using the JAXP <a href='Templates.html'>Templates</a>
mechanism.
</div>
<h3>Architecture</h3>
<div>
When given a stylesheet source, this implementation compiles it internally
into a Stylesheet object, which is a container for templates and state.
Each stylesheet instruction is represented by a subclass of TemplateNode,
which is arranged in a directed graph: each TemplateNode has a reference
to its first child and the next node.
</div>
<div>
The transformation process consists of identifying the Template that matches
the root of the source context, and calling <code>apply</code> on its
corresponding TemplateNode. This in turn processes its children and next
TemplateNode, depending on the semantics of each node type.
</div>
<div>
Template nodes may reference XPath expressions or patterns. These are fully
compiled to objects of type <a href='../xpath/Expr.html'>Expr</a> at the
time the stylesheet is compiled.
</div>
<h3>Conformance</h3>
<div>
This implementation is feature complete, but the XSLT specification is
large and there are still many bugs that need to be ironed out. It has
been tested against the OASIS XSLT TC test suite, comprising unit tests
from the Xalan project and Microsoft. Conformance to these unit tests
is approximately 70% at the current time, although normal usage of the
transformer should involve relatively few surprises (the test suite is
designed to test very complex and obscure functionality).
</div>
<h3>Known bugs</h3>
<ul>
<li>When reusing stylesheets using the JAXP Templates mechanism, XSL
<code>apply-imports</code> instructions will not work.</li>
<li>XPath filter expressions do not always work as expected (this is a
problem with the GNU XPath implementation rather than the transformer).
This can result in problems with the <code>position()</code> function,
as well as <code>select</code> expressions and numbering.</li>
</ul>
<div>
Obviously we'd like to improve conformance and fix these bugs. If you're
interested in working on any of these issues please
<a href='mailto:classpathx-xml@gnu.org'>contact us</a>.
</div>
</body>
</html>