diff options
author | Tom Tromey <tromey@redhat.com> | 2005-02-02 00:42:32 +0000 |
---|---|---|
committer | Tom Tromey <tromey@gcc.gnu.org> | 2005-02-02 00:42:32 +0000 |
commit | 9ecd03471f54de5411794e6fc58c48420564c192 (patch) | |
tree | d6f5216c5e8b86e821ab50a8cb46c7eec16e0a52 /libjava/gnu/xml/transform | |
parent | c1c5b5e383b7e566b49b4c160a1af16eb9222f52 (diff) | |
download | gcc-9ecd03471f54de5411794e6fc58c48420564c192.zip gcc-9ecd03471f54de5411794e6fc58c48420564c192.tar.gz gcc-9ecd03471f54de5411794e6fc58c48420564c192.tar.bz2 |
Makefile.am: New file.
* external/w3c_dom/Makefile.am: New file.
* external/w3c_dom/Makefile.in: New file.
* external/sax/Makefile.am: New file.
* external/sax/Makefile.in: New file.
* external/Makefile.in: New file.
* external/Makefile.am: New file.
* external/README: New file from Classpath.
* configure, aclocal.m4, Makefile.in: Rebuilt.
* configure.ac (AC_CONFIG_FILES): Create new Makefiles.
* Makefile.am (SUBDIRS): Added external.
(toolexeclib_LTLIBRARIES): Removed lib-org-xml-sax.la,
lib-org-w3c-dom.la, lib-org-ietf-gss.la.
(BOOTCLASSPATH): New variable.
(AM_GCJFLAGS): Use it.
(gnu_xml_source_files): New variable.
(libgcj_la_SOURCES): Use it.
(libgcj_la_LDADD): Include new convenience libraries.
(lib_org_ietf_jgss_la_SOURCES): Removed.
(lib_org_ietf_jgss_la_DEPENDENCIES): Likewise.
(lib_org_ietf_jgss_la_LIBADD): Likewise.
(lib_org_w3c_dom_la_SOURCES): Removed.
(lib_org_w3c_dom_la_DEPENDENCIES): Likewise.
(lib_org_w3c_dom_la_LIBADD): Likewise.
(lib_org_xml_sax_la_SOURCES): Removed.
(lib_org_xml_sax_la_DEPENDENCIES): Likewise.
(lib_org_xml_sax_la_LIBADD): Likewise.
(all_java_source_files): Updated.
(property_files): Likewise.
(libgcj-@gcc_version@.jar): Include classes from external/.
(javax_source_files): Updated.
(ordinary_java_source_files): Updated.
* javax/xml/XMLConstants.java,
javax/xml/datatype/DatatypeConfigurationException.java,
javax/xml/datatype/DatatypeConstants.java,
javax/xml/datatype/DatatypeFactory.java,
javax/xml/datatype/Duration.java,
javax/xml/datatype/XMLGregorianCalendar.java,
javax/xml/datatype/package.html,
javax/xml/namespace/NamespaceContext.java,
javax/xml/namespace/QName.java, javax/xml/namespace/package.html,
javax/xml/parsers/DocumentBuilder.java,
javax/xml/parsers/DocumentBuilderFactory.java,
javax/xml/parsers/FactoryConfigurationError.java,
javax/xml/parsers/ParserConfigurationException.java,
javax/xml/parsers/SAXParser.java,
javax/xml/parsers/SAXParserFactory.java,
javax/xml/parsers/package.html,
javax/xml/transform/ErrorListener.java,
javax/xml/transform/OutputKeys.java,
javax/xml/transform/Result.java, javax/xml/transform/Source.java,
javax/xml/transform/SourceLocator.java,
javax/xml/transform/Templates.java,
javax/xml/transform/Transformer.java,
javax/xml/transform/TransformerConfigurationException.java,
javax/xml/transform/TransformerException.java,
javax/xml/transform/TransformerFactory.java,
javax/xml/transform/TransformerFactoryConfigurationError.java,
javax/xml/transform/URIResolver.java,
javax/xml/transform/package.html,
javax/xml/transform/dom/DOMLocator.java,
javax/xml/transform/dom/DOMResult.java,
javax/xml/transform/dom/DOMSource.java,
javax/xml/transform/dom/package.html,
javax/xml/transform/sax/SAXResult.java,
javax/xml/transform/sax/SAXSource.java,
javax/xml/transform/sax/SAXTransformerFactory.java,
javax/xml/transform/sax/TemplatesHandler.java,
javax/xml/transform/sax/TransformerHandler.java,
javax/xml/transform/sax/package.html,
javax/xml/transform/stream/StreamResult.java,
javax/xml/transform/stream/StreamSource.java,
javax/xml/transform/stream/package.html,
javax/xml/validation/Schema.java,
javax/xml/validation/SchemaFactory.java,
javax/xml/validation/TypeInfoProvider.java,
javax/xml/validation/Validator.java,
javax/xml/validation/ValidatorHandler.java,
javax/xml/validation/package.html, javax/xml/xpath/XPath.java,
javax/xml/xpath/XPathConstants.java,
javax/xml/xpath/XPathException.java,
javax/xml/xpath/XPathExpression.java,
javax/xml/xpath/XPathExpressionException.java,
javax/xml/xpath/XPathFactory.java,
javax/xml/xpath/XPathFactoryConfigurationException.java,
javax/xml/xpath/XPathFunction.java,
javax/xml/xpath/XPathFunctionException.java,
javax/xml/xpath/XPathFunctionResolver.java,
javax/xml/xpath/XPathVariableResolver.java,
javax/xml/xpath/package.html: New files, from GNU JAXP.
* org/w3c/dom/Attr.java, org/w3c/dom/CDATASection.java,
org/w3c/dom/CharacterData.java, org/w3c/dom/Comment.java,
org/w3c/dom/DOMException.java, org/w3c/dom/DOMImplementation.java,
org/w3c/dom/Document.java, org/w3c/dom/DocumentFragment.java,
org/w3c/dom/DocumentType.java, org/w3c/dom/Element.java,
org/w3c/dom/Entity.java, org/w3c/dom/EntityReference.java,
org/w3c/dom/NamedNodeMap.java, org/w3c/dom/Node.java,
org/w3c/dom/NodeList.java, org/w3c/dom/Notation.java,
org/w3c/dom/ProcessingInstruction.java, org/w3c/dom/Text.java,
org/w3c/dom/ranges/DocumentRange.java,
org/w3c/dom/ranges/Range.java,
org/w3c/dom/ranges/RangeException.java,
org/w3c/dom/traversal/DocumentTraversal.java,
org/w3c/dom/traversal/NodeFilter.java,
org/w3c/dom/traversal/NodeIterator.java,
org/w3c/dom/traversal/TreeWalker.java,
org/xml/sax/AttributeList.java, org/xml/sax/Attributes.java,
org/xml/sax/ContentHandler.java, org/xml/sax/DTDHandler.java,
org/xml/sax/DocumentHandler.java, org/xml/sax/EntityResolver.java,
org/xml/sax/ErrorHandler.java, org/xml/sax/HandlerBase.java,
org/xml/sax/InputSource.java, org/xml/sax/Locator.java,
org/xml/sax/Parser.java, org/xml/sax/SAXException.java,
org/xml/sax/SAXNotRecognizedException.java,
org/xml/sax/SAXNotSupportedException.java,
org/xml/sax/SAXParseException.java, org/xml/sax/XMLFilter.java,
org/xml/sax/XMLReader.java, org/xml/sax/package.html,
org/xml/sax/ext/DeclHandler.java,
org/xml/sax/ext/LexicalHandler.java, org/xml/sax/ext/package.html,
org/xml/sax/helpers/AttributeListImpl.java,
org/xml/sax/helpers/AttributesImpl.java,
org/xml/sax/helpers/DefaultHandler.java,
org/xml/sax/helpers/LocatorImpl.java,
org/xml/sax/helpers/NamespaceSupport.java,
org/xml/sax/helpers/NewInstance.java,
org/xml/sax/helpers/ParserAdapter.java,
org/xml/sax/helpers/ParserFactory.java,
org/xml/sax/helpers/XMLFilterImpl.java,
org/xml/sax/helpers/XMLReaderAdapter.java,
org/xml/sax/helpers/XMLReaderFactory.java,
org/xml/sax/helpers/package.html: Moved to external/.
* external/sax/README,
external/sax/org/xml/sax/AttributeList.java,
external/sax/org/xml/sax/Attributes.java,
external/sax/org/xml/sax/ContentHandler.java,
external/sax/org/xml/sax/DTDHandler.java,
external/sax/org/xml/sax/DocumentHandler.java,
external/sax/org/xml/sax/EntityResolver.java,
external/sax/org/xml/sax/ErrorHandler.java,
external/sax/org/xml/sax/HandlerBase.java,
external/sax/org/xml/sax/InputSource.java,
external/sax/org/xml/sax/Locator.java,
external/sax/org/xml/sax/Parser.java,
external/sax/org/xml/sax/SAXException.java,
external/sax/org/xml/sax/SAXNotRecognizedException.java,
external/sax/org/xml/sax/SAXNotSupportedException.java,
external/sax/org/xml/sax/SAXParseException.java,
external/sax/org/xml/sax/XMLFilter.java,
external/sax/org/xml/sax/XMLReader.java,
external/sax/org/xml/sax/package.html,
external/sax/org/xml/sax/ext/Attributes2.java,
external/sax/org/xml/sax/ext/Attributes2Impl.java,
external/sax/org/xml/sax/ext/DeclHandler.java,
external/sax/org/xml/sax/ext/DefaultHandler2.java,
external/sax/org/xml/sax/ext/EntityResolver2.java,
external/sax/org/xml/sax/ext/LexicalHandler.java,
external/sax/org/xml/sax/ext/Locator2.java,
external/sax/org/xml/sax/ext/Locator2Impl.java,
external/sax/org/xml/sax/ext/package.html,
external/sax/org/xml/sax/helpers/AttributeListImpl.java,
external/sax/org/xml/sax/helpers/AttributesImpl.java,
external/sax/org/xml/sax/helpers/DefaultHandler.java,
external/sax/org/xml/sax/helpers/LocatorImpl.java,
external/sax/org/xml/sax/helpers/NamespaceSupport.java,
external/sax/org/xml/sax/helpers/NewInstance.java,
external/sax/org/xml/sax/helpers/ParserAdapter.java,
external/sax/org/xml/sax/helpers/ParserFactory.java,
external/sax/org/xml/sax/helpers/XMLFilterImpl.java,
external/sax/org/xml/sax/helpers/XMLReaderAdapter.java,
external/sax/org/xml/sax/helpers/XMLReaderFactory.java,
external/sax/org/xml/sax/helpers/package.html,
external/w3c_dom/COPYRIGHT.html, external/w3c_dom/README,
external/w3c_dom/org/w3c/dom/Attr.java,
external/w3c_dom/org/w3c/dom/CDATASection.java,
external/w3c_dom/org/w3c/dom/CharacterData.java,
external/w3c_dom/org/w3c/dom/Comment.java,
external/w3c_dom/org/w3c/dom/DOMConfiguration.java,
external/w3c_dom/org/w3c/dom/DOMError.java,
external/w3c_dom/org/w3c/dom/DOMErrorHandler.java,
external/w3c_dom/org/w3c/dom/DOMException.java,
external/w3c_dom/org/w3c/dom/DOMImplementation.java,
external/w3c_dom/org/w3c/dom/DOMImplementationList.java,
external/w3c_dom/org/w3c/dom/DOMImplementationSource.java,
external/w3c_dom/org/w3c/dom/DOMLocator.java,
external/w3c_dom/org/w3c/dom/DOMStringList.java,
external/w3c_dom/org/w3c/dom/Document.java,
external/w3c_dom/org/w3c/dom/DocumentFragment.java,
external/w3c_dom/org/w3c/dom/DocumentType.java,
external/w3c_dom/org/w3c/dom/Element.java,
external/w3c_dom/org/w3c/dom/Entity.java,
external/w3c_dom/org/w3c/dom/EntityReference.java,
external/w3c_dom/org/w3c/dom/NameList.java,
external/w3c_dom/org/w3c/dom/NamedNodeMap.java,
external/w3c_dom/org/w3c/dom/Node.java,
external/w3c_dom/org/w3c/dom/NodeList.java,
external/w3c_dom/org/w3c/dom/Notation.java,
external/w3c_dom/org/w3c/dom/ProcessingInstruction.java,
external/w3c_dom/org/w3c/dom/Text.java,
external/w3c_dom/org/w3c/dom/TypeInfo.java,
external/w3c_dom/org/w3c/dom/UserDataHandler.java,
external/w3c_dom/org/w3c/dom/bootstrap/DOMImplementationRegistry.java,
external/w3c_dom/org/w3c/dom/css/CSS2Properties.java,
external/w3c_dom/org/w3c/dom/css/CSSCharsetRule.java,
external/w3c_dom/org/w3c/dom/css/CSSFontFaceRule.java,
external/w3c_dom/org/w3c/dom/css/CSSImportRule.java,
external/w3c_dom/org/w3c/dom/css/CSSMediaRule.java,
external/w3c_dom/org/w3c/dom/css/CSSPageRule.java,
external/w3c_dom/org/w3c/dom/css/CSSPrimitiveValue.java,
external/w3c_dom/org/w3c/dom/css/CSSRule.java,
external/w3c_dom/org/w3c/dom/css/CSSRuleList.java,
external/w3c_dom/org/w3c/dom/css/CSSStyleDeclaration.java,
external/w3c_dom/org/w3c/dom/css/CSSStyleRule.java,
external/w3c_dom/org/w3c/dom/css/CSSStyleSheet.java,
external/w3c_dom/org/w3c/dom/css/CSSUnknownRule.java,
external/w3c_dom/org/w3c/dom/css/CSSValue.java,
external/w3c_dom/org/w3c/dom/css/CSSValueList.java,
external/w3c_dom/org/w3c/dom/css/Counter.java,
external/w3c_dom/org/w3c/dom/css/DOMImplementationCSS.java,
external/w3c_dom/org/w3c/dom/css/DocumentCSS.java,
external/w3c_dom/org/w3c/dom/css/ElementCSSInlineStyle.java,
external/w3c_dom/org/w3c/dom/css/RGBColor.java,
external/w3c_dom/org/w3c/dom/css/Rect.java,
external/w3c_dom/org/w3c/dom/css/ViewCSS.java,
external/w3c_dom/org/w3c/dom/events/DocumentEvent.java,
external/w3c_dom/org/w3c/dom/events/Event.java,
external/w3c_dom/org/w3c/dom/events/EventException.java,
external/w3c_dom/org/w3c/dom/events/EventListener.java,
external/w3c_dom/org/w3c/dom/events/EventTarget.java,
external/w3c_dom/org/w3c/dom/events/MouseEvent.java,
external/w3c_dom/org/w3c/dom/events/MutationEvent.java,
external/w3c_dom/org/w3c/dom/events/UIEvent.java,
external/w3c_dom/org/w3c/dom/html2/HTMLAnchorElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLAppletElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLAreaElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLBRElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLBaseElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLBaseFontElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLBodyElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLButtonElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLCollection.java,
external/w3c_dom/org/w3c/dom/html2/HTMLDListElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLDirectoryElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLDivElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLDocument.java,
external/w3c_dom/org/w3c/dom/html2/HTMLElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLFieldSetElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLFontElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLFormElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLFrameElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLFrameSetElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLHRElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLHeadElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLHeadingElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLHtmlElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLIFrameElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLImageElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLInputElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLIsIndexElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLLIElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLLabelElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLLegendElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLLinkElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLMapElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLMenuElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLMetaElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLModElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLOListElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLObjectElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLOptGroupElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLOptionElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLOptionsCollection.java,
external/w3c_dom/org/w3c/dom/html2/HTMLParagraphElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLParamElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLPreElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLQuoteElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLScriptElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLSelectElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLStyleElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLTableCaptionElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLTableCellElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLTableColElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLTableElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLTableRowElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLTableSectionElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLTextAreaElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLTitleElement.java,
external/w3c_dom/org/w3c/dom/html2/HTMLUListElement.java,
external/w3c_dom/org/w3c/dom/ls/DOMImplementationLS.java,
external/w3c_dom/org/w3c/dom/ls/LSException.java,
external/w3c_dom/org/w3c/dom/ls/LSInput.java,
external/w3c_dom/org/w3c/dom/ls/LSLoadEvent.java,
external/w3c_dom/org/w3c/dom/ls/LSOutput.java,
external/w3c_dom/org/w3c/dom/ls/LSParser.java,
external/w3c_dom/org/w3c/dom/ls/LSParserFilter.java,
external/w3c_dom/org/w3c/dom/ls/LSProgressEvent.java,
external/w3c_dom/org/w3c/dom/ls/LSResourceResolver.java,
external/w3c_dom/org/w3c/dom/ls/LSSerializer.java,
external/w3c_dom/org/w3c/dom/ls/LSSerializerFilter.java,
external/w3c_dom/org/w3c/dom/ranges/DocumentRange.java,
external/w3c_dom/org/w3c/dom/ranges/Range.java,
external/w3c_dom/org/w3c/dom/ranges/RangeException.java,
external/w3c_dom/org/w3c/dom/stylesheets/DocumentStyle.java,
external/w3c_dom/org/w3c/dom/stylesheets/LinkStyle.java,
external/w3c_dom/org/w3c/dom/stylesheets/MediaList.java,
external/w3c_dom/org/w3c/dom/stylesheets/StyleSheet.java,
external/w3c_dom/org/w3c/dom/stylesheets/StyleSheetList.java,
external/w3c_dom/org/w3c/dom/traversal/DocumentTraversal.java,
external/w3c_dom/org/w3c/dom/traversal/NodeFilter.java,
external/w3c_dom/org/w3c/dom/traversal/NodeIterator.java,
external/w3c_dom/org/w3c/dom/traversal/TreeWalker.java,
external/w3c_dom/org/w3c/dom/views/AbstractView.java,
external/w3c_dom/org/w3c/dom/views/DocumentView.java,
external/w3c_dom/org/w3c/dom/xpath/XPathEvaluator.java,
external/w3c_dom/org/w3c/dom/xpath/XPathException.java,
external/w3c_dom/org/w3c/dom/xpath/XPathExpression.java,
external/w3c_dom/org/w3c/dom/xpath/XPathNSResolver.java,
external/w3c_dom/org/w3c/dom/xpath/XPathNamespace.java,
external/w3c_dom/org/w3c/dom/xpath/XPathResult.java: New files
from Classpath.
From-SVN: r94577
Diffstat (limited to 'libjava/gnu/xml/transform')
51 files changed, 10513 insertions, 0 deletions
diff --git a/libjava/gnu/xml/transform/AbstractNumberNode.java b/libjava/gnu/xml/transform/AbstractNumberNode.java new file mode 100644 index 0000000..097637e --- /dev/null +++ b/libjava/gnu/xml/transform/AbstractNumberNode.java @@ -0,0 +1,321 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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 children, TemplateNode next, + TemplateNode format, String lang, + int letterValue, String groupingSeparator, + int groupingSize) + { + super(children, next); + 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 String toString() + { + StringBuffer buf = new StringBuffer(getClass().getName()); + buf.append('['); + buf.append("format="); + buf.append(format); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/gnu/xml/transform/ApplyImportsNode.java b/libjava/gnu/xml/transform/ApplyImportsNode.java new file mode 100644 index 0000000..2b28655 --- /dev/null +++ b/libjava/gnu/xml/transform/ApplyImportsNode.java @@ -0,0 +1,91 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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.text.DecimalFormat; +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>apply-imports</code> instruction. + * + * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a> + */ +final class ApplyImportsNode + extends TemplateNode +{ + + ApplyImportsNode(TemplateNode children, TemplateNode next) + { + super(children, next); + } + + TemplateNode clone(Stylesheet stylesheet) + { + return new ApplyImportsNode((children == null) ? null : + children.clone(stylesheet), + (next == null) ? null : + next.clone(stylesheet)); + } + + 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); + } + } + +} + diff --git a/libjava/gnu/xml/transform/ApplyTemplatesNode.java b/libjava/gnu/xml/transform/ApplyTemplatesNode.java new file mode 100644 index 0000000..83e7c55 --- /dev/null +++ b/libjava/gnu/xml/transform/ApplyTemplatesNode.java @@ -0,0 +1,193 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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 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(TemplateNode children, TemplateNode next, + Expr select, QName mode, + List sortKeys, List withParams, boolean isDefault) + { + super(children, next); + 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)); + } + return new ApplyTemplatesNode((children == null) ? null : + children.clone(stylesheet), + (next == null) ? null : + next.clone(stylesheet), + select.clone(stylesheet), + mode, sortKeys2, withParams2, isDefault); + } + + 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) + { + // push the parameter context + stylesheet.bindings.push(false); + // set the parameters + for (Iterator i = withParams.iterator(); i.hasNext(); ) + { + WithParam p = (WithParam) i.next(); + Object value = p.getValue(stylesheet, mode, context, pos, len); + stylesheet.bindings.set(p.name, value, false); + } + } + 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) + { + if (stylesheet.debug) + { + System.err.println("Applying " + t); + } + stylesheet.current = node; + t.apply(stylesheet, effectiveMode, node, i + 1, l, + parent, nextSibling); + } + } + if (withParams != null) + { + // pop the variable context + stylesheet.bindings.pop(false); + } + } + // apply-templates doesn't have processable children + if (next != null) + { + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + } + + 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(); + } + +} diff --git a/libjava/gnu/xml/transform/AttributeNode.java b/libjava/gnu/xml/transform/AttributeNode.java new file mode 100644 index 0000000..c4409db --- /dev/null +++ b/libjava/gnu/xml/transform/AttributeNode.java @@ -0,0 +1,246 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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 children, TemplateNode next, TemplateNode name, + TemplateNode namespace, Node source) + { + super(children, next); + this.name = name; + this.namespace = namespace; + this.source = source; + } + + TemplateNode clone(Stylesheet stylesheet) + { + return new AttributeNode((children == null) ? null : + children.clone(stylesheet), + (next == null) ? null : next.clone(stylesheet), + name.clone(stylesheet), + (namespace == null) ? null : + namespace.clone(stylesheet), + source); + } + + 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 String toString() + { + StringBuffer buf = new StringBuffer(getClass().getName()); + buf.append('['); + buf.append("name="); + buf.append(name); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/gnu/xml/transform/AttributeSet.java b/libjava/gnu/xml/transform/AttributeSet.java new file mode 100644 index 0000000..92869d1 --- /dev/null +++ b/libjava/gnu/xml/transform/AttributeSet.java @@ -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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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); + } + +} + diff --git a/libjava/gnu/xml/transform/Bindings.java b/libjava/gnu/xml/transform/Bindings.java new file mode 100644 index 0000000..f898a72 --- /dev/null +++ b/libjava/gnu/xml/transform/Bindings.java @@ -0,0 +1,246 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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.transform.TransformerException; +import javax.xml.xpath.XPathVariableResolver; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; + +/** + * 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 +{ + + final Stylesheet stylesheet; + + /** + * Global variables. + */ + final LinkedList variables; + + /** + * Parameter value stack. + */ + final LinkedList parameters; + + Bindings(Stylesheet stylesheet) + { + this.stylesheet = stylesheet; + variables = new LinkedList(); + parameters = new LinkedList(); + push(true); + push(false); + } + + public Object clone() + { + try + { + return (Bindings) super.clone(); + } + catch (CloneNotSupportedException e) + { + throw new Error(e.getMessage()); + } + } + + void push(boolean global) + { + if (global) + { + variables.addFirst(new HashMap()); + } + else + { + parameters.addFirst(new HashMap()); + } + } + + void pop(boolean global) + { + if (global) + { + variables.removeFirst(); + } + else + { + parameters.removeFirst(); + } + } + + public boolean containsKey(String name, boolean global) + { + Iterator i = global ? variables.iterator() : parameters.iterator(); + while (i.hasNext()) + { + Map ctx = (Map) i.next(); + if (ctx.containsKey(name)) + { + return true; + } + } + return false; + } + + public Object get(String name, Node context, int pos, int len) + { + //System.err.println("bindings.get: "+name); + //System.err.println("\t"+toString()); + Object ret = null; + for (Iterator i = variables.iterator(); i.hasNext() && ret == null; ) + { + Map vctx = (Map) i.next(); + ret = vctx.get(name); + } + if (ret == null) + { + for (Iterator i = parameters.iterator(); i.hasNext() && ret == null; ) + { + Map pctx = (Map) i.next(); + ret = pctx.get(name); + } + } + /*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(String name, Object value, boolean global) + { + if (global) + { + Map context = (Map) variables.getFirst(); + context.put(name, value); + } + else + { + Map context = (Map) parameters.getFirst(); + context.put(name, value); + } + } + + public Object resolveVariable(QName qName) + { + return get(qName.toString(), null, 1, 1); + } + + public String toString() + { + StringBuffer buf = new StringBuffer(); + boolean next = false; + Collection seen = new HashSet(); + 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); + } + } + } + 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(); + } +} diff --git a/libjava/gnu/xml/transform/CallTemplateNode.java b/libjava/gnu/xml/transform/CallTemplateNode.java new file mode 100644 index 0000000..ee64e2e --- /dev/null +++ b/libjava/gnu/xml/transform/CallTemplateNode.java @@ -0,0 +1,130 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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.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(TemplateNode children, TemplateNode next, + QName name, List withParams) + { + super(children, next); + 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)); + } + return new CallTemplateNode((children == null) ? null : + children.clone(stylesheet), + (next == null) ? null : + next.clone(stylesheet), + name, withParams2); + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + if (withParams != null) + { + // push the parameter context + stylesheet.bindings.push(false); + // set the parameters + for (Iterator i = withParams.iterator(); i.hasNext(); ) + { + WithParam p = (WithParam) i.next(); + Object value = p.getValue(stylesheet, mode, context, pos, len); + stylesheet.bindings.set(p.name, value, false); + } + } + 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(false); + } + // call-template doesn't have processable children + 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(); + } + +} diff --git a/libjava/gnu/xml/transform/ChooseNode.java b/libjava/gnu/xml/transform/ChooseNode.java new file mode 100644 index 0000000..76b0d8d --- /dev/null +++ b/libjava/gnu/xml/transform/ChooseNode.java @@ -0,0 +1,93 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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 +{ + + ChooseNode(TemplateNode children, TemplateNode next) + { + super(children, next); + } + + TemplateNode clone(Stylesheet stylesheet) + { + return new ChooseNode((children == null) ? null : + children.clone(stylesheet), + (next == null) ? null : + next.clone(stylesheet)); + } + + 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(); + } + +} diff --git a/libjava/gnu/xml/transform/CommentNode.java b/libjava/gnu/xml/transform/CommentNode.java new file mode 100644 index 0000000..99870cd --- /dev/null +++ b/libjava/gnu/xml/transform/CommentNode.java @@ -0,0 +1,115 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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 +{ + + CommentNode(TemplateNode children, TemplateNode next) + { + super(children, next); + } + + TemplateNode clone(Stylesheet stylesheet) + { + return new CommentNode((children == null) ? null : + children.clone(stylesheet), + (next == null) ? null : + next.clone(stylesheet)); + } + + 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(); + } + +} diff --git a/libjava/gnu/xml/transform/CopyNode.java b/libjava/gnu/xml/transform/CopyNode.java new file mode 100644 index 0000000..d06a0af --- /dev/null +++ b/libjava/gnu/xml/transform/CopyNode.java @@ -0,0 +1,179 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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(TemplateNode children, TemplateNode next, String uas) + { + super(children, next); + this.uas = uas; + } + + TemplateNode clone(Stylesheet stylesheet) + { + return new CopyNode((children == null) ? null : + children.clone(stylesheet), + (next == null) ? null : + next.clone(stylesheet), + uas); + } + + 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(); + } + +} diff --git a/libjava/gnu/xml/transform/CopyOfNode.java b/libjava/gnu/xml/transform/CopyOfNode.java new file mode 100644 index 0000000..7ca1006 --- /dev/null +++ b/libjava/gnu/xml/transform/CopyOfNode.java @@ -0,0 +1,179 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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(TemplateNode children, TemplateNode next, Expr select) + { + super(children, next); + this.select = select; + } + + TemplateNode clone(Stylesheet stylesheet) + { + return new CopyOfNode((children == null) ? null : + children.clone(stylesheet), + (next == null) ? null : + next.clone(stylesheet), + select.clone(stylesheet)); + } + + 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 String toString() + { + StringBuffer buf = new StringBuffer(getClass().getName()); + buf.append('['); + buf.append("select="); + buf.append(select); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/gnu/xml/transform/CurrentFunction.java b/libjava/gnu/xml/transform/CurrentFunction.java new file mode 100644 index 0000000..0c901be --- /dev/null +++ b/libjava/gnu/xml/transform/CurrentFunction.java @@ -0,0 +1,98 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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.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 String toString() + { + return "current()"; + } + +} + diff --git a/libjava/gnu/xml/transform/DOMSourceLocator.java b/libjava/gnu/xml/transform/DOMSourceLocator.java new file mode 100644 index 0000000..b9ef705 --- /dev/null +++ b/libjava/gnu/xml/transform/DOMSourceLocator.java @@ -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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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; + } + +} diff --git a/libjava/gnu/xml/transform/DocumentFunction.java b/libjava/gnu/xml/transform/DocumentFunction.java new file mode 100644 index 0000000..03f22b4 --- /dev/null +++ b/libjava/gnu/xml/transform/DocumentFunction.java @@ -0,0 +1,249 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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.InputStream; +import java.io.IOException; +import java.net.URL; +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.transform.ErrorListener; +import javax.xml.transform.TransformerException; +import javax.xml.transform.URIResolver; +import javax.xml.transform.dom.DOMSource; +import javax.xml.xpath.XPathFunction; +import javax.xml.xpath.XPathFunctionException; +import org.w3c.dom.Document; +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; + } + +} diff --git a/libjava/gnu/xml/transform/ElementAvailableFunction.java b/libjava/gnu/xml/transform/ElementAvailableFunction.java new file mode 100644 index 0000000..0c9ce44 --- /dev/null +++ b/libjava/gnu/xml/transform/ElementAvailableFunction.java @@ -0,0 +1,169 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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.List; +import java.util.TreeSet; +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; + } + +} + diff --git a/libjava/gnu/xml/transform/ElementNode.java b/libjava/gnu/xml/transform/ElementNode.java new file mode 100644 index 0000000..305989c0 --- /dev/null +++ b/libjava/gnu/xml/transform/ElementNode.java @@ -0,0 +1,279 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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 children, TemplateNode next, TemplateNode name, + TemplateNode namespace, String uas, Node source) + { + super(children, next); + 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) + { + return new ElementNode((children == null) ? null : + children.clone(stylesheet), + (next == null) ? null : + next.clone(stylesheet), + name.clone(stylesheet), + (namespace == null) ? null : + namespace.clone(stylesheet), + uas, source); + } + + 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 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(); + } + +} diff --git a/libjava/gnu/xml/transform/ErrorListenerErrorHandler.java b/libjava/gnu/xml/transform/ErrorListenerErrorHandler.java new file mode 100644 index 0000000..929f7f0 --- /dev/null +++ b/libjava/gnu/xml/transform/ErrorListenerErrorHandler.java @@ -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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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); + } + } + +} diff --git a/libjava/gnu/xml/transform/ForEachNode.java b/libjava/gnu/xml/transform/ForEachNode.java new file mode 100644 index 0000000..af96628 --- /dev/null +++ b/libjava/gnu/xml/transform/ForEachNode.java @@ -0,0 +1,149 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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(TemplateNode children, TemplateNode next, Expr select, + List sortKeys) + { + super(children, next); + 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)); + } + return new ForEachNode((children == null) ? null : + children.clone(stylesheet), + (next == null) ? null : + next.clone(stylesheet), + select.clone(stylesheet), + sortKeys2); + } + + 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 String toString() + { + StringBuffer buf = new StringBuffer(getClass().getName()); + buf.append('['); + buf.append("select="); + buf.append(select); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/gnu/xml/transform/FormatNumberFunction.java b/libjava/gnu/xml/transform/FormatNumberFunction.java new file mode 100644 index 0000000..73c5af4 --- /dev/null +++ b/libjava/gnu/xml/transform/FormatNumberFunction.java @@ -0,0 +1,133 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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.text.DecimalFormatSymbols; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +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 ¤ 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; + } + +} + diff --git a/libjava/gnu/xml/transform/FunctionAvailableFunction.java b/libjava/gnu/xml/transform/FunctionAvailableFunction.java new file mode 100644 index 0000000..2931082 --- /dev/null +++ b/libjava/gnu/xml/transform/FunctionAvailableFunction.java @@ -0,0 +1,175 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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.List; +import java.util.TreeSet; +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>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; + } + +} + diff --git a/libjava/gnu/xml/transform/GenerateIdFunction.java b/libjava/gnu/xml/transform/GenerateIdFunction.java new file mode 100644 index 0000000..9e48f79 --- /dev/null +++ b/libjava/gnu/xml/transform/GenerateIdFunction.java @@ -0,0 +1,126 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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.List; +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; + } + +} + diff --git a/libjava/gnu/xml/transform/IfNode.java b/libjava/gnu/xml/transform/IfNode.java new file mode 100644 index 0000000..c977348 --- /dev/null +++ b/libjava/gnu/xml/transform/IfNode.java @@ -0,0 +1,107 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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(TemplateNode children, TemplateNode next, Expr test) + { + super(children, next); + this.test = test; + } + + TemplateNode clone(Stylesheet stylesheet) + { + return new IfNode((children == null) ? null : + children.clone(stylesheet), + (next == null) ? null : + next.clone(stylesheet), + test.clone(stylesheet)); + } + + 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 String toString() + { + StringBuffer buf = new StringBuffer(getClass().getName()); + buf.append('['); + buf.append("test="); + buf.append(test); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/gnu/xml/transform/Key.java b/libjava/gnu/xml/transform/Key.java new file mode 100644 index 0000000..008400f --- /dev/null +++ b/libjava/gnu/xml/transform/Key.java @@ -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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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)); + } + +} + diff --git a/libjava/gnu/xml/transform/KeyFunction.java b/libjava/gnu/xml/transform/KeyFunction.java new file mode 100644 index 0000000..233c12f --- /dev/null +++ b/libjava/gnu/xml/transform/KeyFunction.java @@ -0,0 +1,216 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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; + } + +} + diff --git a/libjava/gnu/xml/transform/LiteralNode.java b/libjava/gnu/xml/transform/LiteralNode.java new file mode 100644 index 0000000..1b5af1a --- /dev/null +++ b/libjava/gnu/xml/transform/LiteralNode.java @@ -0,0 +1,225 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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(TemplateNode children, TemplateNode next, Node source) + { + super(children, next); + 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) + { + return new LiteralNode((children == null) ? null : + children.clone(stylesheet), + (next == null) ? null : + next.clone(stylesheet), + source); + } + + 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--; + } + } + } + result = doc.adoptNode(result); + if (result == null) + { + String msg = "Error adopting node to result tree"; + DOMSourceLocator l = new DOMSourceLocator(context); + throw new TransformerException(msg, l); + } + } + 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(); + } + +} diff --git a/libjava/gnu/xml/transform/MessageNode.java b/libjava/gnu/xml/transform/MessageNode.java new file mode 100644 index 0000000..c79060a --- /dev/null +++ b/libjava/gnu/xml/transform/MessageNode.java @@ -0,0 +1,97 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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(TemplateNode children, TemplateNode next, boolean terminate) + { + super(children, next); + this.terminate = terminate; + } + + TemplateNode clone(Stylesheet stylesheet) + { + return new MessageNode((children == null) ? null : + children.clone(stylesheet), + (next == null) ? null : + next.clone(stylesheet), + terminate); + } + + 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); + } + } + +} diff --git a/libjava/gnu/xml/transform/NodeNumberNode.java b/libjava/gnu/xml/transform/NodeNumberNode.java new file mode 100644 index 0000000..76f8d7e --- /dev/null +++ b/libjava/gnu/xml/transform/NodeNumberNode.java @@ -0,0 +1,261 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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.Document; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.NodeTypeTest; +import gnu.xml.xpath.Pattern; +import gnu.xml.xpath.Selector; +import gnu.xml.xpath.Test; +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(TemplateNode children, TemplateNode next, + int level, Pattern count, Pattern from, + TemplateNode format, String lang, + int letterValue, String groupingSeparator, int groupingSize) + { + super(children, next, format, lang, letterValue, groupingSeparator, + groupingSize); + this.level = level; + this.count = count; + this.from = from; + } + + TemplateNode clone(Stylesheet stylesheet) + { + return new NodeNumberNode((children == null) ? null : + children.clone(stylesheet), + (next == null) ? null : + next.clone(stylesheet), + level, + (count == null) ? null : + (Pattern) count.clone(stylesheet), + (from == null) ? from : + (Pattern) from.clone(stylesheet), + format, lang, letterValue, + groupingSeparator, groupingSize); + } + + 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(); + String nn = current.getLocalName(); + 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; + } + +} diff --git a/libjava/gnu/xml/transform/NumberNode.java b/libjava/gnu/xml/transform/NumberNode.java new file mode 100644 index 0000000..0970ac9 --- /dev/null +++ b/libjava/gnu/xml/transform/NumberNode.java @@ -0,0 +1,86 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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.Document; +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(TemplateNode children, TemplateNode next, + Expr value, TemplateNode format, String lang, + int letterValue, String groupingSeparator, int groupingSize) + { + super(children, next, format, lang, letterValue, groupingSeparator, + groupingSize); + this.value = value; + } + + TemplateNode clone(Stylesheet stylesheet) + { + return new NumberNode((children == null) ? null : + children.clone(stylesheet), + (next == null) ? null : + next.clone(stylesheet), + value.clone(stylesheet), + format, lang, letterValue, + groupingSeparator, groupingSize); + } + + 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() }; + } + +} diff --git a/libjava/gnu/xml/transform/OtherwiseNode.java b/libjava/gnu/xml/transform/OtherwiseNode.java new file mode 100644 index 0000000..1d9590e --- /dev/null +++ b/libjava/gnu/xml/transform/OtherwiseNode.java @@ -0,0 +1,93 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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 +{ + + OtherwiseNode(TemplateNode children, TemplateNode next) + { + super(children, next); + } + + TemplateNode clone(Stylesheet stylesheet) + { + return new OtherwiseNode((children == null) ? null : + children.clone(stylesheet), + (next == null) ? null : + next.clone(stylesheet)); + } + + 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(); + } + +} diff --git a/libjava/gnu/xml/transform/ParameterNode.java b/libjava/gnu/xml/transform/ParameterNode.java new file mode 100644 index 0000000..5b766d5 --- /dev/null +++ b/libjava/gnu/xml/transform/ParameterNode.java @@ -0,0 +1,156 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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 +{ + + final String name; + final Expr select; + final boolean global; + + ParameterNode(TemplateNode children, TemplateNode next, + String name, Expr select, boolean global) + { + super(children, next); + this.name = name; + this.select = select; + this.global = global; + } + + TemplateNode clone(Stylesheet stylesheet) + { + return new ParameterNode((children == null) ? null : + children.clone(stylesheet), + (next == null) ? null : + next.clone(stylesheet), + name, + select.clone(stylesheet), + global); + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + boolean apply = global || !stylesheet.bindings.containsKey(name, global); + if (apply) + { + // push the variable context + stylesheet.bindings.push(global); + // set the variable + Object value = getValue(stylesheet, mode, context, pos, len); + if (value != null) + { + stylesheet.bindings.set(name, value, global); + } + } + // 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); + } + if (apply) + { + // pop the variable context + stylesheet.bindings.pop(global); + } + } + + 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 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); + } + if (global) + { + buf.append(",global"); + } + buf.append(']'); + return buf.toString(); + } + +} + diff --git a/libjava/gnu/xml/transform/ProcessingInstructionNode.java b/libjava/gnu/xml/transform/ProcessingInstructionNode.java new file mode 100644 index 0000000..1eb2bd6 --- /dev/null +++ b/libjava/gnu/xml/transform/ProcessingInstructionNode.java @@ -0,0 +1,123 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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(TemplateNode children, TemplateNode next, + String name) + { + super(children, next); + this.name = name; + } + + TemplateNode clone(Stylesheet stylesheet) + { + return new ProcessingInstructionNode((children == null) ? null : + children.clone(stylesheet), + (next == null) ? null : + next.clone(stylesheet), + name); + } + + 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(); + } + +} diff --git a/libjava/gnu/xml/transform/SAXSerializer.java b/libjava/gnu/xml/transform/SAXSerializer.java new file mode 100644 index 0000000..c5e3820 --- /dev/null +++ b/libjava/gnu/xml/transform/SAXSerializer.java @@ -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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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); + } + } + +} diff --git a/libjava/gnu/xml/transform/SortKey.java b/libjava/gnu/xml/transform/SortKey.java new file mode 100644 index 0000000..9ecc919 --- /dev/null +++ b/libjava/gnu/xml/transform/SortKey.java @@ -0,0 +1,154 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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; + } + } + +} diff --git a/libjava/gnu/xml/transform/StreamSerializer.java b/libjava/gnu/xml/transform/StreamSerializer.java new file mode 100644 index 0000000..136105a --- /dev/null +++ b/libjava/gnu/xml/transform/StreamSerializer.java @@ -0,0 +1,632 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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.util.Collection; +import java.util.Collections; +import java.util.HashMap; +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; // = + + protected String encoding; + boolean compatibilityMode; + 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(); + compatibilityMode = true; + if (encoding.length() > 3) + { + String p = encoding.substring(0, 3); + if (p.equalsIgnoreCase("UTF") || + p.equalsIgnoreCase("UCS")) + { + compatibilityMode = false; + } + } + 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(final Node node, final OutputStream out, + boolean convertToCdata) + throws IOException + { + if (out == null) + { + throw new NullPointerException("no output stream"); + } + String value, prefix; + Node children; + Node next = node.getNextSibling(); + 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; + } + define(nsuri, node.getLocalName()); + } + 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)) + { + 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 && + "head".equalsIgnoreCase(ctx.getLocalName())) + { + 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 && + "meta".equalsIgnoreCase(ctx.getLocalName())) + { + 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); + 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); + } + if (next != null) + { + serialize(next, out, convertToCdata); + } + } + + 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 UnsupportedEncodingException + { + if (compatibilityMode) + { + int len = text.length(); + StringBuffer buf = null; + for (int i = 0; i < len; i++) + { + char c = text.charAt(i); + if (c >= 127) + { + 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); + } + } + if (buf != null) + { + text = buf.toString(); + } + } + return text.getBytes(encoding); + } + + 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("<"); + } + else if (c == '>') + { + if (buf == null) + { + buf = new StringBuffer(text.substring(0, i)); + } + buf.append(">"); + } + 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("&"); + } + } + else if (c == '\'' && inAttr) + { + if (buf == null) + { + buf = new StringBuffer(text.substring(0, i)); + } + buf.append("'"); + } + else if (c == '"' && inAttr) + { + if (buf == null) + { + buf = new StringBuffer(text.substring(0, i)); + } + buf.append("""); + } + 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()); + } + } + +} diff --git a/libjava/gnu/xml/transform/Stylesheet.java b/libjava/gnu/xml/transform/Stylesheet.java new file mode 100644 index 0000000..80f5781 --- /dev/null +++ b/libjava/gnu/xml/transform/Stylesheet.java @@ -0,0 +1,1730 @@ +/* Stylesheet.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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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.text.DecimalFormatSymbols; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.TreeSet; +import javax.xml.XMLConstants; +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.transform.Source; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathFunction; +import javax.xml.xpath.XPathFunctionResolver; +import javax.xml.xpath.XPathExpressionException; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.w3c.dom.UserDataHandler; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.NameTest; +import gnu.xml.xpath.NodeTypeTest; +import gnu.xml.xpath.Pattern; +import gnu.xml.xpath.Selector; +import gnu.xml.xpath.Root; +import gnu.xml.xpath.Test; +import gnu.xml.xpath.XPathImpl; + +/** + * An XSL stylesheet. + * + * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a> + */ +class Stylesheet + implements NamespaceContext, XPathFunctionResolver, UserDataHandler, Cloneable +{ + + static final String XSL_NS = "http://www.w3.org/1999/XSL/Transform"; + + static final int OUTPUT_XML = 0; + static final int OUTPUT_HTML = 1; + static final int OUTPUT_TEXT = 2; + + final TransformerFactoryImpl factory; + TransformerImpl transformer; + Stylesheet parent; + final XPathImpl xpath; + final String systemId; + final int precedence; + + final boolean debug; + + /** + * Version of XSLT. + */ + String version; + + Collection extensionElementPrefixes; + Collection excludeResultPrefixes; + + /** + * Set of element names for which we should strip whitespace. + */ + Set stripSpace; + + /** + * Set of element names for which we should preserve whitespace. + */ + Set preserveSpace; + + /** + * Output options. + */ + int outputMethod; + String outputVersion; + String outputEncoding; + boolean outputOmitXmlDeclaration; + boolean outputStandalone; + String outputPublicId; + String outputSystemId; + Collection outputCdataSectionElements; + boolean outputIndent; + String outputMediaType; + + /** + * Keys. + */ + Collection keys; + + /** + * Decimal formats. + */ + Map decimalFormats; + + /** + * Namespace aliases. + */ + Map namespaceAliases; + + /** + * Attribute-sets. + */ + List attributeSets; + + /** + * Variables. + */ + List variables; + + /** + * Variable and parameter bindings. + */ + Bindings bindings; + + /** + * Templates. + */ + LinkedList templates; + + TemplateNode builtInNodeTemplate; + TemplateNode builtInTextTemplate; + + /** + * Holds the current node while parsing. + * Necessary to associate the document function with its declaring node, + * to resolve namespaces, and to maintain the current node for the + * current() function. + */ + Node current; + + /** + * Set by a terminating message. + */ + transient boolean terminated; + + /** + * Current template in force. + */ + transient Template currentTemplate; + + Stylesheet(TransformerFactoryImpl factory, + Stylesheet parent, + Document doc, + String systemId, + int precedence) + throws TransformerConfigurationException + { + this.factory = factory; + this.systemId = systemId; + this.precedence = precedence; + this.parent = parent; + extensionElementPrefixes = new HashSet(); + excludeResultPrefixes = new HashSet(); + stripSpace = new LinkedHashSet(); + preserveSpace = new LinkedHashSet(); + outputCdataSectionElements = new LinkedHashSet(); + xpath = (XPathImpl) factory.xpathFactory.newXPath(); + if (parent == null) + { + bindings = new Bindings(this); + attributeSets = new LinkedList(); + variables = new LinkedList(); + namespaceAliases = new LinkedHashMap(); + templates = new LinkedList(); + keys = new LinkedList(); + decimalFormats = new LinkedHashMap(); + initDefaultDecimalFormat(); + xpath.setNamespaceContext(this); + xpath.setXPathFunctionResolver(this); + } + else + { + /* Test for import circularity */ + for (Stylesheet ctx = this; ctx.parent != null; ctx = ctx.parent) + { + if (systemId != null && systemId.equals(ctx.parent.systemId)) + { + String msg = "circularity importing " + systemId; + throw new TransformerConfigurationException(msg); + } + } + /* OK */ + Stylesheet root = getRootStylesheet(); + bindings = root.bindings; + attributeSets = root.attributeSets; + variables = root.variables; + namespaceAliases = root.namespaceAliases; + templates = root.templates; + keys = root.keys; + decimalFormats = root.decimalFormats; + xpath.setNamespaceContext(root); + xpath.setXPathFunctionResolver(root); + } + xpath.setXPathVariableResolver(bindings); + + Test anyNode = new NodeTypeTest((short) 0); + List tests = Collections.singletonList(anyNode); + builtInNodeTemplate = + new ApplyTemplatesNode(null, null, + new Selector(Selector.CHILD, tests), + null, null, null, true); + builtInTextTemplate = + new ValueOfNode(null, null, + new Selector(Selector.SELF, tests), + false); + + parse(doc.getDocumentElement(), true); + current = doc; // Alow namespace resolution during processing + + debug = ("yes".equals(System.getProperty("xsl.debug"))); + + if (debug) + { + System.err.println("Stylesheet: " + doc.getDocumentURI()); + for (Iterator i = templates.iterator(); i.hasNext(); ) + { + Template t = (Template) i.next(); + t.list(System.err); + System.err.println("--------------------"); + } + } + } + + Stylesheet getRootStylesheet() + { + Stylesheet stylesheet = this; + while (stylesheet.parent != null) + { + stylesheet = stylesheet.parent; + } + return stylesheet; + } + + void initDefaultDecimalFormat() + { + DecimalFormat defaultDecimalFormat = new DecimalFormat(); + DecimalFormatSymbols symbols = new DecimalFormatSymbols(); + symbols.setDecimalSeparator('.'); + symbols.setGroupingSeparator(','); + symbols.setPercent('%'); + symbols.setPerMill('\u2030'); + symbols.setZeroDigit('0'); + symbols.setDigit('#'); + symbols.setPatternSeparator(';'); + symbols.setInfinity("Infinity"); + symbols.setNaN("NaN"); + symbols.setMinusSign('-'); + defaultDecimalFormat.setDecimalFormatSymbols(symbols); + decimalFormats.put(null, defaultDecimalFormat); + } + + // -- Cloneable -- + + public Object clone() + { + try + { + Stylesheet clone = (Stylesheet) super.clone(); + clone.bindings = (Bindings) bindings.clone(); + + LinkedList templates2 = new LinkedList(); + for (Iterator i = templates.iterator(); i.hasNext(); ) + { + Template t = (Template) i.next(); + templates2.add(t.clone(clone)); + } + clone.templates = templates2; + + LinkedList attributeSets2 = new LinkedList(); + for (Iterator i = attributeSets.iterator(); i.hasNext(); ) + { + AttributeSet as = (AttributeSet) i.next(); + attributeSets2.add(as.clone(clone)); + } + clone.attributeSets = attributeSets2; + + LinkedList variables2 = new LinkedList(); + for (Iterator i = variables.iterator(); i.hasNext(); ) + { + ParameterNode var = (ParameterNode) i.next(); + variables2.add(var.clone(clone)); + } + clone.variables = variables2; + + LinkedList keys2 = new LinkedList(); + for (Iterator i = keys.iterator(); i.hasNext(); ) + { + Key k = (Key) i.next(); + keys2.add(k.clone(clone)); + } + clone.keys = keys2; + + return clone; + } + catch (CloneNotSupportedException e) + { + throw new Error(e.getMessage()); + } + } + + // -- Variable evaluation -- + + void initTopLevelVariables(Node context) + throws TransformerException + { + for (Iterator i = variables.iterator(); i.hasNext(); ) + { + ParameterNode var = (ParameterNode) i.next(); + bindings.set(var.name, + var.getValue(this, null, context, 1, 1), + var.global); + } + } + + // -- NamespaceContext -- + + public String getNamespaceURI(String prefix) + { + return (current == null) ? null : current.lookupNamespaceURI(prefix); + } + + public String getPrefix(String namespaceURI) + { + return (current == null) ? null : current.lookupPrefix(namespaceURI); + } + + public Iterator getPrefixes(String namespaceURI) + { + // TODO + return Collections.singleton(getPrefix(namespaceURI)).iterator(); + } + + // -- Template selection -- + + TemplateNode getTemplate(QName mode, Node context, boolean applyImports) + throws TransformerException + { + //System.err.println("getTemplate: mode="+mode+" context="+context); + Set candidates = new TreeSet(); + for (Iterator j = templates.iterator(); j.hasNext(); ) + { + Template t = (Template) j.next(); + boolean isMatch = t.matches(mode, context); + if (applyImports) + { + if (currentTemplate == null) + { + String msg = "current template may not be null " + + "during apply-imports"; + throw new TransformerException(msg); + } + if (!currentTemplate.imports(t)) + { + isMatch = false; + } + } + //System.err.println("\t"+context+" "+t+"="+isMatch); + if (isMatch) + { + candidates.add(t); + } + } + //System.err.println("\tcandidates="+candidates); + if (candidates.isEmpty()) + { + // Apply built-in template + // Current template is unchanged + //System.err.println("\tbuiltInTemplate context="+context); + switch (context.getNodeType()) + { + case Node.ELEMENT_NODE: + case Node.DOCUMENT_NODE: + case Node.DOCUMENT_FRAGMENT_NODE: + case Node.PROCESSING_INSTRUCTION_NODE: + case Node.COMMENT_NODE: + return builtInNodeTemplate; + case Node.TEXT_NODE: + case Node.ATTRIBUTE_NODE: + return builtInTextTemplate; + default: + return null; + } + } + else + { + Template t = (Template) candidates.iterator().next(); + // Set current template + currentTemplate = t; + //System.err.println("\ttemplate="+t+" context="+context); + return t.node; + } + } + + TemplateNode getTemplate(QName mode, QName name) + throws TransformerException + { + //System.err.println("getTemplate: mode="+mode+" name="+name); + Set candidates = new TreeSet(); + for (Iterator j = templates.iterator(); j.hasNext(); ) + { + Template t = (Template) j.next(); + boolean isMatch = t.matches(name); + //System.err.println("\t"+name+" "+t+"="+isMatch); + if (isMatch) + { + candidates.add(t); + } + } + if (candidates.isEmpty()) + { + return null; + //throw new TransformerException("template '" + name + "' not found"); + } + Template t = (Template) candidates.iterator().next(); + //System.err.println("\ttemplate="+t+" context="+context); + return t.node; + } + + /** + * template + */ + final Template parseTemplate(Node node, NamedNodeMap attrs) + throws TransformerConfigurationException, XPathExpressionException + { + String n = getAttribute(attrs, "name"); + QName name = (n == null) ? null : getQName(n); + String m = getAttribute(attrs, "match"); + Pattern match = null; + if (m != null) + { + try + { + match = (Pattern) xpath.compile(m); + } + catch (ClassCastException e) + { + String msg = "illegal pattern: " + m; + throw new TransformerConfigurationException(msg); + } + } + String p = getAttribute(attrs, "priority"); + String mm = getAttribute(attrs, "mode"); + QName mode = (mm == null) ? null : getQName(mm); + double priority = (p == null) ? Template.DEFAULT_PRIORITY : + Double.parseDouble(p); + return new Template(this, name, match, parse(node.getFirstChild()), + precedence, priority, mode); + } + + /** + * output + */ + final void parseOutput(Node node, NamedNodeMap attrs) + throws TransformerConfigurationException + { + String method = getAttribute(attrs, "method"); + if ("xml".equals(method) || method == null) + { + outputMethod = OUTPUT_XML; + } + else if ("html".equals(method)) + { + outputMethod = OUTPUT_HTML; + } + else if ("text".equals(method)) + { + outputMethod = OUTPUT_TEXT; + } + else + { + String msg = "unsupported output method: " + method; + DOMSourceLocator l = new DOMSourceLocator(node); + throw new TransformerConfigurationException(msg, l); + } + outputPublicId = getAttribute(attrs, "public-id"); + outputSystemId = getAttribute(attrs, "system-id"); + outputEncoding = getAttribute(attrs, "encoding"); + String indent = getAttribute(attrs, "indent"); + if (indent != null) + { + outputIndent = "yes".equals(indent); + } + outputVersion = getAttribute(attrs, "version"); + String omitXmlDecl = getAttribute(attrs, "omit-xml-declaration"); + if (omitXmlDecl != null) + { + outputOmitXmlDeclaration = "yes".equals(omitXmlDecl); + } + String standalone = getAttribute(attrs, "standalone"); + if (standalone != null) + { + outputStandalone = "yes".equals(standalone); + } + outputMediaType = getAttribute(attrs, "media-type"); + String cdataSectionElements = + getAttribute(attrs, "cdata-section-elements"); + if (cdataSectionElements != null) + { + StringTokenizer st = new StringTokenizer(cdataSectionElements, " "); + while (st.hasMoreTokens()) + { + outputCdataSectionElements.add(st.nextToken()); + } + } + } + + /** + * key + */ + final void parseKey(Node node, NamedNodeMap attrs) + throws TransformerConfigurationException, XPathExpressionException + { + String n = getRequiredAttribute(attrs, "name", node); + String m = getRequiredAttribute(attrs, "match", node); + String u = getRequiredAttribute(attrs, "use", node); + QName name = getQName(n); + Expr use = (Expr) xpath.compile(u); + try + { + Pattern match = (Pattern) xpath.compile(m); + Key key = new Key(name, match, use); + keys.add(key); + } + catch (ClassCastException e) + { + throw new TransformerConfigurationException("invalid pattern: " + m); + } + } + + /** + * decimal-format + */ + final void parseDecimalFormat(Node node, NamedNodeMap attrs) + throws TransformerConfigurationException + { + String dfName = getAttribute(attrs, "name"); + DecimalFormat df = new DecimalFormat(); + DecimalFormatSymbols symbols = new DecimalFormatSymbols(); + symbols.setDecimalSeparator(parseDFChar(attrs, "decimal-separator", '.')); + symbols.setGroupingSeparator(parseDFChar(attrs, "grouping-separator", ',')); + symbols.setInfinity(parseDFString(attrs, "infinity", "Infinity")); + symbols.setMinusSign(parseDFChar(attrs, "minus-sign", '-')); + symbols.setNaN(parseDFString(attrs, "NaN", "NaN")); + symbols.setPercent(parseDFChar(attrs, "percent", '%')); + symbols.setPerMill(parseDFChar(attrs, "per-mille", '\u2030')); + symbols.setZeroDigit(parseDFChar(attrs, "zero-digit", '0')); + symbols.setDigit(parseDFChar(attrs, "digit", '#')); + symbols.setPatternSeparator(parseDFChar(attrs, "pattern-separator", ';')); + df.setDecimalFormatSymbols(symbols); + decimalFormats.put(dfName, df); + } + + private final char parseDFChar(NamedNodeMap attrs, String name, char def) + throws TransformerConfigurationException + { + Node attr = attrs.getNamedItem(name); + try + { + return (attr == null) ? def : attr.getNodeValue().charAt(0); + } + catch (StringIndexOutOfBoundsException e) + { + throw new TransformerConfigurationException("empty attribute '" + + name + + "' in decimal-format", e); + } + } + + private final String parseDFString(NamedNodeMap attrs, String name, + String def) + { + Node attr = attrs.getNamedItem(name); + return (attr == null) ? def : attr.getNodeValue(); + } + + /** + * namespace-alias + */ + final void parseNamespaceAlias(Node node, NamedNodeMap attrs) + throws TransformerConfigurationException + { + String sp = getRequiredAttribute(attrs, "stylesheet-prefix", node); + String rp = getRequiredAttribute(attrs, "result-prefix", node); + namespaceAliases.put(sp, rp); + } + + /** + * attribute-set + */ + final void parseAttributeSet(Node node, NamedNodeMap attrs) + throws TransformerConfigurationException, XPathExpressionException + { + TemplateNode children = parse(node.getFirstChild()); + String name = getRequiredAttribute(attrs, "name", node); + String uas = getAttribute(attrs, "use-attribute-sets"); + attributeSets.add(new AttributeSet(children, name, uas)); + } + + /** + * Parse top-level elements. + */ + void parse(Node node, boolean root) + throws TransformerConfigurationException + { + if (node == null) + { + return; + } + current = node; + try + { + String namespaceUri = node.getNamespaceURI(); + if (XSL_NS.equals(namespaceUri) && + node.getNodeType() == Node.ELEMENT_NODE) + { + String name = node.getLocalName(); + NamedNodeMap attrs = node.getAttributes(); + if ("stylesheet".equals(name)) + { + version = getAttribute(attrs, "version"); + String eep = getAttribute(attrs, "extension-element-prefixes"); + if (eep != null) + { + StringTokenizer st = new StringTokenizer(eep); + while (st.hasMoreTokens()) + { + extensionElementPrefixes.add(st.nextToken()); + } + } + String erp = getAttribute(attrs, "exclude-result-prefixes"); + if (erp != null) + { + StringTokenizer st = new StringTokenizer(erp); + while (st.hasMoreTokens()) + { + excludeResultPrefixes.add(st.nextToken()); + } + } + parse(node.getFirstChild(), false); + return; + } + else if ("template".equals(name)) + { + templates.addFirst(parseTemplate(node, attrs)); + } + else if ("param".equals(name) || + "variable".equals(name)) + { + boolean global = "variable".equals(name); + TemplateNode content = parse(node.getFirstChild()); + String paramName = getRequiredAttribute(attrs, "name", node); + String select = getAttribute(attrs, "select"); + if (select != null && select.length() > 0) + { + if (content != null) + { + String msg = "parameter '" + paramName + + "' has both select and content"; + DOMSourceLocator l = new DOMSourceLocator(node); + throw new TransformerConfigurationException(msg, l); + } + Expr expr = (Expr) xpath.compile(select); + variables.add(new ParameterNode(null, null, + paramName, + expr, global)); + } + else + { + variables.add(new ParameterNode(content, null, + paramName, + null, global)); + } + bindings.set(paramName, content, global); + } + else if ("include".equals(name) || "import".equals(name)) + { + int delta = "import".equals(name) ? -1 : 0; + String href = getRequiredAttribute(attrs, "href", node); + Source source; + synchronized (factory.resolver) + { + if (transformer != null) + { + factory.resolver + .setUserResolver(transformer.getURIResolver()); + factory.resolver + .setUserListener(transformer.getErrorListener()); + } + source = factory.resolver.resolve(systemId, href); + } + factory.newStylesheet(source, precedence + delta, this); + } + else if ("output".equals(name)) + { + parseOutput(node, attrs); + } + else if ("preserve-space".equals(name)) + { + String elements = + getRequiredAttribute(attrs, "elements", node); + StringTokenizer st = new StringTokenizer(elements, + " \t\n\r"); + while (st.hasMoreTokens()) + { + preserveSpace.add(parseNameTest(st.nextToken())); + } + } + else if ("strip-space".equals(name)) + { + String elements = + getRequiredAttribute(attrs, "elements", node); + StringTokenizer st = new StringTokenizer(elements, + " \t\n\r"); + while (st.hasMoreTokens()) + { + stripSpace.add(parseNameTest(st.nextToken())); + } + } + else if ("key".equals(name)) + { + parseKey(node, attrs); + } + else if ("decimal-format".equals(name)) + { + parseDecimalFormat(node, attrs); + } + else if ("namespace-alias".equals(name)) + { + parseNamespaceAlias(node, attrs); + } + else if ("attribute-set".equals(name)) + { + parseAttributeSet(node, attrs); + } + parse(node.getNextSibling(), false); + } + else if (root) + { + // Literal document element + Attr versionNode = + ((Element)node).getAttributeNodeNS(XSL_NS, "version"); + if (versionNode == null) + { + String msg = "no xsl:version attribute on literal result node"; + DOMSourceLocator l = new DOMSourceLocator(node); + throw new TransformerConfigurationException(msg, l); + } + version = versionNode.getValue(); + Node rootClone = node.cloneNode(true); + NamedNodeMap attrs = rootClone.getAttributes(); + attrs.removeNamedItemNS(XSL_NS, "version"); + templates.add(new Template(this, null, new Root(), + parse(rootClone), + precedence, + Template.DEFAULT_PRIORITY, + null)); + } + else + { + // Skip unknown elements, text, comments, etc + parse(node.getNextSibling(), false); + } + } + catch (TransformerException e) + { + DOMSourceLocator l = new DOMSourceLocator(node); + throw new TransformerConfigurationException(e.getMessage(), l, e); + } + catch (DOMException e) + { + DOMSourceLocator l = new DOMSourceLocator(node); + throw new TransformerConfigurationException(e.getMessage(), l, e); + } + catch (XPathExpressionException e) + { + DOMSourceLocator l = new DOMSourceLocator(node); + throw new TransformerConfigurationException(e.getMessage(), l, e); + } + } + + final NameTest parseNameTest(String token) + { + if ("*".equals(token)) + { + return new NameTest(null, true, true); + } + else if (token.endsWith(":*")) + { + QName qName = getQName(token.substring(0, token.length() - 2)); + return new NameTest(qName, true, false); + } + else + { + QName qName = getQName(token); + return new NameTest(qName, false, false); + } + } + + final QName getQName(String name) + { + QName qName = QName.valueOf(name); + String prefix = qName.getPrefix(); + String uri = qName.getNamespaceURI(); + if (prefix != null && (uri == null || uri.length() == 0)) + { + uri = getNamespaceURI(prefix); + String localName = qName.getLocalPart(); + qName = new QName(uri, localName, prefix); + } + return qName; + } + + final TemplateNode parseAttributeValueTemplate(String value, Node source) + throws TransformerConfigurationException, XPathExpressionException + { + current = source; + // Tokenize + int len = value.length(); + int off = 0; + List tokens = new ArrayList(); // text tokens + List types = new ArrayList(); // literal or expression + int depth = 0; + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c == '{') + { + if (i < (len - 1) && value.charAt(i + 1) == '{') + { + tokens.add(value.substring(off, i + 1)); + types.add(Boolean.FALSE); + i++; + off = i + 1; + continue; + } + if (depth == 0) + { + if (i - off > 0) + { + tokens.add(value.substring(off, i)); + types.add(Boolean.FALSE); + } + off = i + 1; + } + depth++; + } + else if (c == '}') + { + if (i < (len - 1) && value.charAt(i + 1) == '}') + { + tokens.add(value.substring(off, i + 1)); + types.add(Boolean.FALSE); + i++; + off = i + 1; + continue; + } + if (depth == 1) + { + if (i - off > 0) + { + tokens.add(value.substring(off, i)); + types.add(Boolean.TRUE); + } + else + { + String msg = "attribute value template " + + "must contain expression: " + value; + DOMSourceLocator l = new DOMSourceLocator(source); + throw new TransformerConfigurationException(msg, l); + } + off = i + 1; + } + depth--; + } + } + if (depth > 0) + { + String msg = "invalid attribute value template: " + value; + throw new TransformerConfigurationException(msg); + } + if (len - off > 0) + { + // Trailing text + tokens.add(value.substring(off)); + types.add(Boolean.FALSE); + } + + // Construct template node tree + TemplateNode ret = null; + Document doc = source.getOwnerDocument(); + len = tokens.size(); + for (int i = len - 1; i >= 0; i--) + { + String token = (String) tokens.get(i); + Boolean type = (Boolean) types.get(i); + if (type == Boolean.TRUE) + { + // Expression text + Expr select = (Expr) xpath.compile(token); + ret = new ValueOfNode(null, ret, select, false); + } + else + { + // Verbatim text + ret = new LiteralNode(null, ret, doc.createTextNode(token)); + } + } + return ret; + } + + boolean isPreserved(Text text) + throws TransformerConfigurationException + { + // Check characters in text + String value = text.getData(); + if (value != null) + { + int len = value.length(); + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c != 0x20 && c != 0x09 && c != 0x0a && c != 0x0d) + { + return true; + } + } + } + // Check parent node + Node ctx = text.getParentNode(); + if (!preserveSpace.isEmpty()) + { + for (Iterator i = preserveSpace.iterator(); i.hasNext(); ) + { + NameTest preserveTest = (NameTest) i.next(); + if (preserveTest.matches(ctx, 1, 1)) + { + boolean override = false; + if (!stripSpace.isEmpty()) + { + for (Iterator j = stripSpace.iterator(); j.hasNext(); ) + { + NameTest stripTest = (NameTest) j.next(); + if (stripTest.matches(ctx, 1, 1)) + { + override = true; + break; + } + } + } + if (!override) + { + return true; + } + } + } + } + // Check whether any ancestor specified xml:space + while (ctx != null) + { + if (ctx.getNodeType() == Node.ELEMENT_NODE) + { + Element element = (Element) ctx; + String xmlSpace = element.getAttribute("xml:space"); + if ("default".equals(xmlSpace)) + { + break; + } + else if ("preserve".equals(xmlSpace)) + { + return true; + } + else if (xmlSpace.length() > 0) + { + String msg = "Illegal value for xml:space: " + xmlSpace; + throw new TransformerConfigurationException(msg); + } + else if ("text".equals(ctx.getLocalName()) && + XSL_NS.equals(ctx.getNamespaceURI())) + { + // xsl:text implies xml:space='preserve' + return true; + } + } + ctx = ctx.getParentNode(); + } + return false; + } + + public XPathFunction resolveFunction(QName name, int arity) + { + String uri = name.getNamespaceURI(); + if (XSL_NS.equals(uri) || uri == null || uri.length() == 0) + { + String localName = name.getLocalPart(); + if ("document".equals(localName) && (arity == 1 || arity == 2)) + { + if (current == null) + { + throw new RuntimeException("current is null"); + } + return new DocumentFunction(getRootStylesheet(), current); + } + else if ("key".equals(localName) && (arity == 2)) + { + return new KeyFunction(getRootStylesheet()); + } + else if ("format-number".equals(localName) && + (arity == 2 || arity == 3)) + { + return new FormatNumberFunction(getRootStylesheet()); + } + else if ("current".equals(localName) && (arity == 0)) + { + return new CurrentFunction(getRootStylesheet()); + } + else if ("unparsed-entity-uri".equals(localName) && (arity == 1)) + { + return new UnparsedEntityUriFunction(); + } + else if ("generate-id".equals(localName) && + (arity == 1 || arity == 0)) + { + return new GenerateIdFunction(); + } + else if ("system-property".equals(localName) && (arity == 1)) + { + return new SystemPropertyFunction(); + } + else if ("element-available".equals(localName) && (arity == 1)) + { + return new ElementAvailableFunction(this); + } + else if ("function-available".equals(localName) && (arity == 1)) + { + return new FunctionAvailableFunction(this); + } + } + return null; + } + + // -- Parsing -- + + /** + * apply-templates + */ + final TemplateNode parseApplyTemplates(Node node, Node children, Node next) + throws TransformerConfigurationException, XPathExpressionException + { + NamedNodeMap attrs = node.getAttributes(); + String m = getAttribute(attrs, "mode"); + QName mode = (m == null) ? null : getQName(m); + String s = getAttribute(attrs, "select"); + if (s == null) + { + s = "child::node()"; + } + List sortKeys = parseSortKeys(children); + List withParams = parseWithParams(children); + Expr select = (Expr) xpath.compile(s); + return new ApplyTemplatesNode(null, parse(next), + select, mode, + sortKeys, withParams, false); + } + + /** + * call-template + */ + final TemplateNode parseCallTemplate(Node node, Node children, Node next) + throws TransformerConfigurationException, XPathExpressionException + { + NamedNodeMap attrs = node.getAttributes(); + String n = getRequiredAttribute(attrs, "name", node); + QName name = getQName(n); + List withParams = parseWithParams(children); + return new CallTemplateNode(null, parse(next), name, + withParams); + } + + /** + * value-of + */ + final TemplateNode parseValueOf(Node node, Node children, Node next) + throws TransformerConfigurationException, XPathExpressionException + { + NamedNodeMap attrs = node.getAttributes(); + String s = getRequiredAttribute(attrs, "select", node); + String doe = getAttribute(attrs, "disable-output-escaping"); + boolean d = "yes".equals(doe); + Expr select = (Expr) xpath.compile(s); + return new ValueOfNode(null, parse(next), select, d); + } + + /** + * for-each + */ + final TemplateNode parseForEach(Node node, Node children, Node next) + throws TransformerConfigurationException, XPathExpressionException + { + NamedNodeMap attrs = node.getAttributes(); + String s = getRequiredAttribute(attrs, "select", node); + List sortKeys = parseSortKeys(children); + Expr select = (Expr) xpath.compile(s); + return new ForEachNode(parse(children), parse(next), select, sortKeys); + } + + /** + * if + */ + final TemplateNode parseIf(Node node, Node children, Node next) + throws TransformerConfigurationException, XPathExpressionException + { + NamedNodeMap attrs = node.getAttributes(); + String t = getRequiredAttribute(attrs, "test", node); + Expr test = (Expr) xpath.compile(t); + return new IfNode(parse(children), parse(next), test); + } + + /** + * when + */ + final TemplateNode parseWhen(Node node, Node children, Node next) + throws TransformerConfigurationException, XPathExpressionException + { + NamedNodeMap attrs = node.getAttributes(); + String t = getRequiredAttribute(attrs, "test", node); + Expr test = (Expr) xpath.compile(t); + return new WhenNode(parse(children), parse(next), test); + } + + /** + * element + */ + final TemplateNode parseElement(Node node, Node children, Node next) + throws TransformerConfigurationException, XPathExpressionException + { + NamedNodeMap attrs = node.getAttributes(); + String name = getRequiredAttribute(attrs, "name", node); + String namespace = getAttribute(attrs, "namespace"); + String uas = getAttribute(attrs, "use-attribute-sets"); + TemplateNode n = parseAttributeValueTemplate(name, node); + TemplateNode ns = (namespace == null) ? null : + parseAttributeValueTemplate(namespace, node); + return new ElementNode(parse(children), parse(next), n, ns, uas, node); + } + + /** + * attribute + */ + final TemplateNode parseAttribute(Node node, Node children, Node next) + throws TransformerConfigurationException, XPathExpressionException + { + NamedNodeMap attrs = node.getAttributes(); + String name = getRequiredAttribute(attrs, "name", node); + String namespace = getAttribute(attrs, "namespace"); + TemplateNode n = parseAttributeValueTemplate(name, node); + TemplateNode ns = (namespace == null) ? null : + parseAttributeValueTemplate(namespace, node); + return new AttributeNode(parse(children), parse(next), n, ns, node); + } + + /** + * text + */ + final TemplateNode parseText(Node node, Node children, Node next) + throws TransformerConfigurationException, XPathExpressionException + { + NamedNodeMap attrs = node.getAttributes(); + String doe = getAttribute(attrs, "disable-output-escaping"); + boolean d = "yes".equals(doe); + return new TextNode(parse(children), parse(next), d); + } + + /** + * copy + */ + final TemplateNode parseCopy(Node node, Node children, Node next) + throws TransformerConfigurationException, XPathExpressionException + { + NamedNodeMap attrs = node.getAttributes(); + String uas = getAttribute(attrs, "use-attribute-sets"); + return new CopyNode(parse(children), parse(next), uas); + } + + /** + * processing-instruction + */ + final TemplateNode parseProcessingInstruction(Node node, Node children, + Node next) + throws TransformerConfigurationException, XPathExpressionException + { + NamedNodeMap attrs = node.getAttributes(); + String name = getRequiredAttribute(attrs, "name", node); + return new ProcessingInstructionNode(parse(children), + parse(next), name); + } + + /** + * number + */ + final TemplateNode parseNumber(Node node, Node children, Node next) + throws TransformerConfigurationException, XPathExpressionException + { + NamedNodeMap attrs = node.getAttributes(); + String v = getAttribute(attrs, "value"); + String ff = getAttribute(attrs, "format"); + if (ff == null) + { + ff = "1"; + } + TemplateNode format = parseAttributeValueTemplate(ff, node); + String lang = getAttribute(attrs, "lang"); + String lv = getAttribute(attrs, "letter-value"); + int letterValue = "traditional".equals(lv) ? + AbstractNumberNode.TRADITIONAL : + AbstractNumberNode.ALPHABETIC; + String gs = getAttribute(attrs, "grouping-separator"); + String gz = getAttribute(attrs, "grouping-size"); + int gz2 = (gz != null && gz.length() > 0) ? + Integer.parseInt(gz) : 1; + if (v != null && v.length() > 0) + { + Expr value = (Expr) xpath.compile(v); + return new NumberNode(parse(children), parse(next), + value, format, lang, + letterValue, gs, gz2); + } + else + { + String l = getAttribute(attrs, "level"); + int level = + "multiple".equals(l) ? NodeNumberNode.MULTIPLE : + "any".equals(l) ? NodeNumberNode.ANY : + NodeNumberNode.SINGLE; + String c = getAttribute(attrs, "count"); + String f = getAttribute(attrs, "from"); + Pattern count = null; + Pattern from = null; + if (c != null) + { + try + { + count = (Pattern) xpath.compile(c); + } + catch (ClassCastException e) + { + String msg = "invalid pattern: " + c; + throw new TransformerConfigurationException(msg); + } + } + if (f != null) + { + try + { + from = (Pattern) xpath.compile(f); + } + catch (ClassCastException e) + { + String msg = "invalid pattern: " + f; + throw new TransformerConfigurationException(msg); + } + } + return new NodeNumberNode(parse(children), parse(next), + level, count, from, + format, lang, + letterValue, gs, gz2); + } + } + + /** + * copy-of + */ + final TemplateNode parseCopyOf(Node node, Node children, Node next) + throws TransformerConfigurationException, XPathExpressionException + { + NamedNodeMap attrs = node.getAttributes(); + String s = getRequiredAttribute(attrs, "select", node); + Expr select = (Expr) xpath.compile(s); + return new CopyOfNode(parse(children), parse(next), select); + } + + /** + * message + */ + final TemplateNode parseMessage(Node node, Node children, Node next) + throws TransformerConfigurationException, XPathExpressionException + { + NamedNodeMap attrs = node.getAttributes(); + String t = getAttribute(attrs, "terminate"); + boolean terminate = "yes".equals(t); + return new MessageNode(parse(children), parse(next), terminate); + } + + /** + * Parse template-level elements. + */ + final TemplateNode parse(Node node) + throws TransformerConfigurationException + { + if (node == null) + { + return null; + } + // Hack to associate the document function with its declaring node + current = node; + Node children = node.getFirstChild(); + Node next = node.getNextSibling(); + try + { + String namespaceUri = node.getNamespaceURI(); + if (Stylesheet.XSL_NS.equals(namespaceUri) && + Node.ELEMENT_NODE == node.getNodeType()) + { + String name = node.getLocalName(); + if ("apply-templates".equals(name)) + { + return parseApplyTemplates(node, children, next); + } + else if ("call-template".equals(name)) + { + return parseCallTemplate(node, children, next); + } + else if ("value-of".equals(name)) + { + return parseValueOf(node, children, next); + } + else if ("for-each".equals(name)) + { + return parseForEach(node, children, next); + } + else if ("if".equals(name)) + { + return parseIf(node, children, next); + } + else if ("choose".equals(name)) + { + return new ChooseNode(parse(children), parse(next)); + } + else if ("when".equals(name)) + { + return parseWhen(node, children, next); + } + else if ("otherwise".equals(name)) + { + return new OtherwiseNode(parse(children), parse(next)); + } + else if ("element".equals(name)) + { + return parseElement(node, children, next); + } + else if ("attribute".equals(name)) + { + return parseAttribute(node, children, next); + } + else if ("text".equals(name)) + { + return parseText(node, children, next); + } + else if ("copy".equals(name)) + { + return parseCopy(node, children, next); + } + else if ("processing-instruction".equals(name)) + { + return parseProcessingInstruction(node, children, next); + } + else if ("comment".equals(name)) + { + return new CommentNode(parse(children), parse(next)); + } + else if ("number".equals(name)) + { + return parseNumber(node, children, next); + } + else if ("param".equals(name) || + "variable".equals(name)) + { + boolean global = "variable".equals(name); + NamedNodeMap attrs = node.getAttributes(); + TemplateNode content = parse(children); + String paramName = getRequiredAttribute(attrs, "name", node); + String select = getAttribute(attrs, "select"); + if (select != null) + { + if (content != null) + { + String msg = "parameter '" + paramName + + "' has both select and content"; + DOMSourceLocator l = new DOMSourceLocator(node); + throw new TransformerConfigurationException(msg, l); + } + Expr expr = (Expr) xpath.compile(select); + return new ParameterNode(null, parse(next), + paramName, expr, global); + } + else + { + return new ParameterNode(content, parse(next), + paramName, null, global); + } + } + else if ("copy-of".equals(name)) + { + return parseCopyOf(node, children, next); + } + else if ("message".equals(name)) + { + return parseMessage(node, children, next); + } + else if ("apply-imports".equals(name)) + { + return new ApplyImportsNode(parse(children), parse(next)); + } + else + { + // xsl:fallback + // Pass over any other XSLT nodes + return parse(next); + } + } + String prefix = node.getPrefix(); + if (extensionElementPrefixes.contains(prefix)) + { + // Pass over extension elements + return parse(next); + } + switch (node.getNodeType()) + { + case Node.TEXT_NODE: + // Determine whether to strip whitespace + Text text = (Text) node; + if (!isPreserved(text)) + { + // Strip + text.getParentNode().removeChild(text); + return parse(next); + } + break; + case Node.COMMENT_NODE: + // Ignore comments + return parse(next); + case Node.ELEMENT_NODE: + // Check for attribute value templates and use-attribute-sets + NamedNodeMap attrs = node.getAttributes(); + boolean convert = false; + String useAttributeSets = null; + int len = attrs.getLength(); + for (int i = 0; i < len; i++) + { + Node attr = attrs.item(i); + String value = attr.getNodeValue(); + if (Stylesheet.XSL_NS.equals(attr.getNamespaceURI()) && + "use-attribute-sets".equals(attr.getLocalName())) + { + useAttributeSets = value; + convert = true; + break; + } + int start = value.indexOf('{'); + int end = value.indexOf('}'); + if (start != -1 || end != -1) + { + convert = true; + break; + } + } + if (convert) + { + // Create an element-producing template node instead + // with appropriate attribute-producing child template nodes + TemplateNode child = parse(children); + for (int i = 0; i < len; i++) + { + Node attr = attrs.item(i); + String ans = attr.getNamespaceURI(); + String aname = attr.getNodeName(); + if (Stylesheet.XSL_NS.equals(ans) && + "use-attribute-sets".equals(attr.getLocalName())) + { + continue; + } + String value = attr.getNodeValue(); + TemplateNode grandchild = + parseAttributeValueTemplate(value, node); + TemplateNode n = + parseAttributeValueTemplate(aname, node); + TemplateNode ns = (ans == null) ? null : + parseAttributeValueTemplate(ans, node); + child = new AttributeNode(grandchild, child, n, ns, attr); + } + String ename = node.getNodeName(); + TemplateNode n = parseAttributeValueTemplate(ename, node); + TemplateNode ns = (namespaceUri == null) ? null : + parseAttributeValueTemplate(namespaceUri, node); + return new ElementNode(child, parse(next), + n, ns, useAttributeSets, + node); + } + // Otherwise fall through + break; + } + } + catch (XPathExpressionException e) + { + DOMSourceLocator l = new DOMSourceLocator(node); + throw new TransformerConfigurationException(e.getMessage(), l, e); + } + return new LiteralNode(parse(children), parse(next), node); + } + + final List parseSortKeys(Node node) + throws TransformerConfigurationException, XPathExpressionException + { + List ret = new LinkedList(); + while (node != null) + { + String namespaceUri = node.getNamespaceURI(); + if (Stylesheet.XSL_NS.equals(namespaceUri) && + Node.ELEMENT_NODE == node.getNodeType() && + "sort".equals(node.getLocalName())) + { + NamedNodeMap attrs = node.getAttributes(); + String s = getAttribute(attrs, "select"); + if (s == null) + { + s = "."; + } + Expr select = (Expr) xpath.compile(s); + String l = getAttribute(attrs, "lang"); + TemplateNode lang = (l == null) ? null : + parseAttributeValueTemplate(l, node); + String dt = getAttribute(attrs, "data-type"); + TemplateNode dataType = (dt == null) ? null : + parseAttributeValueTemplate(dt, node); + String o = getAttribute(attrs, "order"); + TemplateNode order = (o == null) ? null : + parseAttributeValueTemplate(o, node); + String co = getAttribute(attrs, "case-order"); + TemplateNode caseOrder = (co == null) ? null : + parseAttributeValueTemplate(co, node); + ret.add(new SortKey(select, lang, dataType, order, caseOrder)); + } + node = node.getNextSibling(); + } + return ret.isEmpty() ? null : ret; + } + + final List parseWithParams(Node node) + throws TransformerConfigurationException, XPathExpressionException + { + List ret = new LinkedList(); + while (node != null) + { + String namespaceUri = node.getNamespaceURI(); + if (Stylesheet.XSL_NS.equals(namespaceUri) && + Node.ELEMENT_NODE == node.getNodeType() && + "with-param".equals(node.getLocalName())) + { + NamedNodeMap attrs = node.getAttributes(); + TemplateNode content = parse(node.getFirstChild()); + String name = getRequiredAttribute(attrs, "name", node); + String select = getAttribute(attrs, "select"); + if (select != null) + { + if (content != null) + { + String msg = "parameter '" + name + + "' has both select and content"; + DOMSourceLocator l = new DOMSourceLocator(node); + throw new TransformerConfigurationException(msg, l); + } + Expr expr = (Expr) xpath.compile(select); + ret.add(new WithParam(name, expr)); + } + else + { + ret.add(new WithParam(name, content)); + } + } + node = node.getNextSibling(); + } + return ret.isEmpty() ? null : ret; + } + + /** + * Created element nodes have a copy of the namespace nodes in the + * stylesheet, except the XSLT namespace, extension namespaces, and + * exclude-result-prefixes. + */ + final void addNamespaceNodes(Node source, Node target, Document doc, + Collection elementExcludeResultPrefixes) + { + NamedNodeMap attrs = source.getAttributes(); + if (attrs != null) + { + int len = attrs.getLength(); + for (int i = 0; i < len; i++) + { + Node attr = attrs.item(i); + String uri = attr.getNamespaceURI(); + if (uri == XMLConstants.XMLNS_ATTRIBUTE_NS_URI) + { + String prefix = attr.getLocalName(); + if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix)) + { + prefix = "#default"; + } + String ns = attr.getNodeValue(); + // Should the namespace be excluded? + if (XSL_NS.equals(ns) || + extensionElementPrefixes.contains(prefix) || + elementExcludeResultPrefixes.contains(prefix) || + excludeResultPrefixes.contains(prefix)) + { + continue; + } + // Is the namespace already defined on the target? + if (prefix == "#default") + { + prefix = null; + } + if (target.lookupNamespaceURI(prefix) != null) + { + continue; + } + attr = attr.cloneNode(true); + attr = doc.adoptNode(attr); + target.getAttributes().setNamedItemNS(attr); + } + } + } + Node parent = source.getParentNode(); + if (parent != null) + { + addNamespaceNodes(parent, target, doc, elementExcludeResultPrefixes); + } + } + + static final String getAttribute(NamedNodeMap attrs, String name) + { + Node attr = attrs.getNamedItem(name); + if (attr == null) + { + return null; + } + String ret = attr.getNodeValue(); + if (ret.length() == 0) + { + return null; + } + return ret; + } + + static final String getRequiredAttribute(NamedNodeMap attrs, String name, + Node source) + throws TransformerConfigurationException + { + String value = getAttribute(attrs, name); + if (value == null || value.length() == 0) + { + String msg = + name + " attribute is required on " + source.getNodeName(); + DOMSourceLocator l = new DOMSourceLocator(source); + throw new TransformerConfigurationException(msg, l); + } + return value; + } + + // Handle user data changes when nodes are cloned etc + + public void handle(short op, String key, Object data, Node src, Node dst) + { + dst.setUserData(key, data, this); + } + +} + diff --git a/libjava/gnu/xml/transform/SystemPropertyFunction.java b/libjava/gnu/xml/transform/SystemPropertyFunction.java new file mode 100644 index 0000000..3d95d21d --- /dev/null +++ b/libjava/gnu/xml/transform/SystemPropertyFunction.java @@ -0,0 +1,129 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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.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; + } + +} + diff --git a/libjava/gnu/xml/transform/Template.java b/libjava/gnu/xml/transform/Template.java new file mode 100644 index 0000000..6aaa4c1 --- /dev/null +++ b/libjava/gnu/xml/transform/Template.java @@ -0,0 +1,254 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.xpath.XPathExpressionException; +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); + } + } + +} diff --git a/libjava/gnu/xml/transform/TemplateNode.java b/libjava/gnu/xml/transform/TemplateNode.java new file mode 100644 index 0000000..1fe37c2 --- /dev/null +++ b/libjava/gnu/xml/transform/TemplateNode.java @@ -0,0 +1,115 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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(); + + final TemplateNode children; + final TemplateNode next; + + TemplateNode(TemplateNode children, TemplateNode next) + { + this.children = children; + this.next = 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()); + } + 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); + + /** + * 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); + } + } + +} diff --git a/libjava/gnu/xml/transform/TemplatesImpl.java b/libjava/gnu/xml/transform/TemplatesImpl.java new file mode 100644 index 0000000..a7403e9 --- /dev/null +++ b/libjava/gnu/xml/transform/TemplatesImpl.java @@ -0,0 +1,83 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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.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.URIResolver; + +/** + * 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(); + } + +} diff --git a/libjava/gnu/xml/transform/TextNode.java b/libjava/gnu/xml/transform/TextNode.java new file mode 100644 index 0000000..70a8ce4 --- /dev/null +++ b/libjava/gnu/xml/transform/TextNode.java @@ -0,0 +1,116 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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(TemplateNode children, TemplateNode next, + boolean disableOutputEscaping) + { + super(children, next); + this.disableOutputEscaping = disableOutputEscaping; + } + + TemplateNode clone(Stylesheet stylesheet) + { + return new TextNode((children == null) ? null : + children.clone(stylesheet), + (next == null) ? null : + next.clone(stylesheet), + disableOutputEscaping); + } + + 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); + } + } + +} diff --git a/libjava/gnu/xml/transform/TransformerFactoryImpl.java b/libjava/gnu/xml/transform/TransformerFactoryImpl.java new file mode 100644 index 0000000..9c4d9da --- /dev/null +++ b/libjava/gnu/xml/transform/TransformerFactoryImpl.java @@ -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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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; + } + +} diff --git a/libjava/gnu/xml/transform/TransformerImpl.java b/libjava/gnu/xml/transform/TransformerImpl.java new file mode 100644 index 0000000..fb4632e --- /dev/null +++ b/libjava/gnu/xml/transform/TransformerImpl.java @@ -0,0 +1,586 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Properties; +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.NamedNodeMap; +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; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.Root; + +/** + * 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(false); + } + } + + 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); + // TODO cdata-section-elements + // TODO 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); + } + // 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) // CDATA sections ? + { + if (!stylesheet.isPreserved((Text) node)) + { + node.getParentNode().removeChild(node); + } + } + 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(name, value, false); + } + } + + public Object getParameter(String name) + { + if (stylesheet != null) + { + return stylesheet.bindings.get(name, null, 1, 1); + } + return null; + } + + public void clearParameters() + { + if (stylesheet != null) + { + stylesheet.bindings.pop(false); + stylesheet.bindings.push(false); + } + } + + 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; + } + +} diff --git a/libjava/gnu/xml/transform/TransformerOutputProperties.java b/libjava/gnu/xml/transform/TransformerOutputProperties.java new file mode 100644 index 0000000..d56e795 --- /dev/null +++ b/libjava/gnu/xml/transform/TransformerOutputProperties.java @@ -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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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; + } + +} + diff --git a/libjava/gnu/xml/transform/URIResolverEntityResolver.java b/libjava/gnu/xml/transform/URIResolverEntityResolver.java new file mode 100644 index 0000000..ef29015 --- /dev/null +++ b/libjava/gnu/xml/transform/URIResolverEntityResolver.java @@ -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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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); + } + } + +} diff --git a/libjava/gnu/xml/transform/UnparsedEntityUriFunction.java b/libjava/gnu/xml/transform/UnparsedEntityUriFunction.java new file mode 100644 index 0000000..41a606e --- /dev/null +++ b/libjava/gnu/xml/transform/UnparsedEntityUriFunction.java @@ -0,0 +1,118 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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.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; + } + +} + diff --git a/libjava/gnu/xml/transform/ValueOfNode.java b/libjava/gnu/xml/transform/ValueOfNode.java new file mode 100644 index 0000000..6027052 --- /dev/null +++ b/libjava/gnu/xml/transform/ValueOfNode.java @@ -0,0 +1,129 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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.text.DecimalFormat; +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(TemplateNode children, TemplateNode next, Expr select, + boolean disableOutputEscaping) + { + super(children, next); + this.select = select; + this.disableOutputEscaping = disableOutputEscaping; + } + + TemplateNode clone(Stylesheet stylesheet) + { + return new ValueOfNode((children == null) ? null : + children.clone(stylesheet), + (next == null) ? null : + next.clone(stylesheet), + select.clone(stylesheet), + disableOutputEscaping); + } + + 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); + String value = Expr._string(context, ret); + //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 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(); + } + +} diff --git a/libjava/gnu/xml/transform/WhenNode.java b/libjava/gnu/xml/transform/WhenNode.java new file mode 100644 index 0000000..f220466 --- /dev/null +++ b/libjava/gnu/xml/transform/WhenNode.java @@ -0,0 +1,110 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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(TemplateNode children, TemplateNode next, Expr test) + { + super(children, next); + this.test = test; + } + + TemplateNode clone(Stylesheet stylesheet) + { + return new WhenNode((children == null) ? null : + children.clone(stylesheet), + (next == null) ? null : + next.clone(stylesheet), + test.clone(stylesheet)); + } + + 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 String toString() + { + StringBuffer buf = new StringBuffer(getClass().getName()); + buf.append('['); + buf.append("test="); + buf.append(test); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/gnu/xml/transform/WithParam.java b/libjava/gnu/xml/transform/WithParam.java new file mode 100644 index 0000000..c8804f8 --- /dev/null +++ b/libjava/gnu/xml/transform/WithParam.java @@ -0,0 +1,110 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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 String name; + final Expr select; + final TemplateNode content; + + WithParam(String name, Expr select) + { + this.name = name; + this.select = select; + content = null; + } + + WithParam(String 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)); + } + } + +} diff --git a/libjava/gnu/xml/transform/XSLComparator.java b/libjava/gnu/xml/transform/XSLComparator.java new file mode 100644 index 0000000..1b76ed6 --- /dev/null +++ b/libjava/gnu/xml/transform/XSLComparator.java @@ -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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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; + } + +} diff --git a/libjava/gnu/xml/transform/XSLURIResolver.java b/libjava/gnu/xml/transform/XSLURIResolver.java new file mode 100644 index 0000000..2603cdd --- /dev/null +++ b/libjava/gnu/xml/transform/XSLURIResolver.java @@ -0,0 +1,270 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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.HttpURLConnection; +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 && 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)); + } + } + 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); + } + } + 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); + } + } + +} + diff --git a/libjava/gnu/xml/transform/package.html b/libjava/gnu/xml/transform/package.html new file mode 100644 index 0000000..d435596 --- /dev/null +++ b/libjava/gnu/xml/transform/package.html @@ -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> |