You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by re...@apache.org on 2009/12/21 14:14:59 UTC
svn commit: r892809 [1/2] - in /cocoon/cocoon3/trunk/cocoon-sax: ./
src/main/java/org/apache/cocoon/sax/component/
src/main/java/org/apache/cocoon/sax/xpointer/ src/main/javacc/
src/test/java/org/apache/cocoon/sax/component/ src/test/resources/
Author: reinhard
Date: Mon Dec 21 13:14:59 2009
New Revision: 892809
URL: http://svn.apache.org/viewvc?rev=892809&view=rev
Log:
COCOON3-3 add XInclude transformer by Simone Tripodi
Added:
cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/XIncludeTransformer.java (with props)
cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/
cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/AbstractPointerPart.java (with props)
cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/PointerPart.java (with props)
cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/ShorthandPart.java (with props)
cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/TransformerHandlerFactory.java (with props)
cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/UnsupportedPart.java (with props)
cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointer.java (with props)
cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointerContext.java (with props)
cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointerPart.java (with props)
cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XmlnsPart.java (with props)
cocoon/cocoon3/trunk/cocoon-sax/src/main/javacc/
cocoon/cocoon3/trunk/cocoon-sax/src/main/javacc/xpointer-fw.jj
cocoon/cocoon3/trunk/cocoon-sax/src/test/java/org/apache/cocoon/sax/component/XIncludeTransformerTest.java (with props)
cocoon/cocoon3/trunk/cocoon-sax/src/test/resources/just-text.txt (with props)
cocoon/cocoon3/trunk/cocoon-sax/src/test/resources/licenses.xml (with props)
cocoon/cocoon3/trunk/cocoon-sax/src/test/resources/xinclude-deprecated_xpointer.xml (with props)
cocoon/cocoon3/trunk/cocoon-sax/src/test/resources/xinclude-fallback.xml (with props)
cocoon/cocoon3/trunk/cocoon-sax/src/test/resources/xinclude-shorthand.xml (with props)
cocoon/cocoon3/trunk/cocoon-sax/src/test/resources/xinclude-text-only.xml (with props)
cocoon/cocoon3/trunk/cocoon-sax/src/test/resources/xinclude-xml.xml (with props)
cocoon/cocoon3/trunk/cocoon-sax/src/test/resources/xinclude-xpointer.xml (with props)
Modified:
cocoon/cocoon3/trunk/cocoon-sax/pom.xml
Modified: cocoon/cocoon3/trunk/cocoon-sax/pom.xml
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sax/pom.xml?rev=892809&r1=892808&r2=892809&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sax/pom.xml (original)
+++ cocoon/cocoon3/trunk/cocoon-sax/pom.xml Mon Dec 21 13:14:59 2009
@@ -29,7 +29,7 @@
<version>3.0.0-alpha-2-SNAPSHOT</version>
<relativePath>../parent</relativePath>
</parent>
-
+
<groupId>org.apache.cocoon.sax</groupId>
<artifactId>cocoon-sax</artifactId>
<version>3.0.0-alpha-2-SNAPSHOT</version>
@@ -89,6 +89,41 @@
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
+ <artifactId>javacc-maven-plugin</artifactId>
+ <version>2.6</version>
+ <executions>
+ <execution>
+ <id>javacc</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>javacc</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.3</version>
+ <executions>
+ <execution>
+ <id>add-source</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>add-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>target/generated-sources/javacc</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
@@ -117,7 +152,17 @@
</plugin>
</plugins>
</build>
-
+
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>javacc-maven-plugin</artifactId>
+ <version>2.6</version>
+ </plugin>
+ </plugins>
+ </reporting>
+
<profiles>
<profile>
<id>it</id>
@@ -129,8 +174,9 @@
<configuration>
<excludes>
<exclude>src/test/resources/META-INF/services/javax.xml.transform.TransformerFactory</exclude>
+ <exclude>src/test/resources/just-text.txt</exclude>
</excludes>
- </configuration>
+ </configuration>
<executions>
<execution>
<phase>verify</phase>
@@ -139,9 +185,9 @@
</goals>
</execution>
</executions>
- </plugin>
+ </plugin>
</plugins>
- </build>
- </profile>
- </profiles>
+ </build>
+ </profile>
+ </profiles>
</project>
Added: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/XIncludeTransformer.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/XIncludeTransformer.java?rev=892809&view=auto
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/XIncludeTransformer.java (added)
+++ cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/XIncludeTransformer.java Mon Dec 21 13:14:59 2009
@@ -0,0 +1,640 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.sax.component;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+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 java.util.Map.Entry;
+
+import org.apache.cocoon.pipeline.ProcessingException;
+import org.apache.cocoon.sax.AbstractSAXTransformer;
+import org.apache.cocoon.sax.SAXConsumer;
+import org.apache.cocoon.sax.util.XMLUtils;
+import org.apache.cocoon.sax.xpointer.ParseException;
+import org.apache.cocoon.sax.xpointer.XPointer;
+import org.apache.cocoon.sax.xpointer.XPointerContext;
+import org.apache.cocoon.sax.xpointer.XPointerFrameworkParser;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+
+/**
+ * $Id$
+ */
+public final class XIncludeTransformer extends AbstractSAXTransformer implements SAXConsumer {
+
+ private static final String XINCLUDE_NAMESPACE_URI = "http://www.w3.org/2001/XInclude";
+
+ private static final String XINCLUDE_INCLUDE = "include";
+
+ private static final String XINCLUDE_FALLBACK = "fallback";
+
+ private static final String XINCLUDE_HREF = "href";
+
+ private static final String XINCLUDE_XPOINTER = "xpointer";
+
+ private static final String XINCLUDE_PARSE = "parse";
+
+ private static final String XINCLUDE_ENCODING = "encoding";
+
+ private static final String DEFAULT_CHARSET = "UTF-8";
+
+ private static final String XINCLUDE_ACCEPT = "accept";
+
+ private static final String XINCLUDE_ACCEPT_LANGUAGE = "accept-language";
+
+ private static final String XINCLUDE_PARSE_XML = "xml";
+
+ private static final String XINCLUDE_PARSE_TEXT = "text";
+
+ private static final String UNKNOWN_LOCATION = "unknow location";
+
+ private static final String HTTP_ACCEPT = "Accept";
+
+ private static final String HTTP_ACCEPT_LANGUAGE = "Accept-Language";
+
+ private static final String CHARSET = "charset=";
+
+ private static final String BASE_URL = "baseUrl";
+
+ private final Log logger = LogFactory.getLog(this.getClass());
+
+ /**
+ * The nesting level of xi:include elements that have been encountered.
+ */
+ private int xIncludeElementLevel = 0;
+
+ /**
+ * The nesting level of fallback that should be used
+ */
+ private int useFallbackLevel = 0;
+
+ /**
+ * The nesting level of xi:fallback elements that have been encountered.
+ */
+ private int fallbackElementLevel;
+
+ /**
+ * Locator of the current stream, stored here so that it can be restored after
+ * another document send its content to the consumer.
+ */
+ private Locator locator;
+
+ private URL baseUrl;
+
+ /**
+ * Keep a map of namespaces prefix in the source document to pass it
+ * to the XPointerContext for correct namespace identification.
+ */
+ private final Map<String, String> namespaces = new HashMap<String, String>();
+
+ public XIncludeTransformer() {
+ // default empty constructor - used in the sitemap
+ }
+
+ /**
+ *
+ * @param baseUrl
+ */
+ public XIncludeTransformer(URL baseUrl) {
+ this.setBaseUrl(baseUrl);
+ }
+
+ @Override
+ public void setConfiguration(Map<String, ? extends Object> configuration) {
+ this.setBaseUrl((URL) configuration.get(BASE_URL));
+ }
+
+ /**
+ *
+ * @param baseUrl
+ */
+ public void setBaseUrl(URL baseUrl) {
+ this.baseUrl = baseUrl;
+ }
+
+ /**
+ * Eventually previous errors don't reset local variables status, so
+ * every time a new consumer is set, local variables should be re-initialized
+ */
+ @Override
+ protected void setSAXConsumer(final SAXConsumer xmlConsumer) {
+ super.setSAXConsumer(xmlConsumer);
+ this.xIncludeElementLevel = 0;
+ this.fallbackElementLevel = 0;
+ this.useFallbackLevel = 0;
+ }
+
+ /**
+ * Determine whether the pipe is currently in a state where contents
+ * should be evaluated, i.e. xi:include elements should be resolved
+ * and elements in other namespaces should be copied through. Will
+ * return false for fallback contents within a successful xi:include,
+ * and true for contents outside any xi:include or within an xi:fallback
+ * for an unsuccessful xi:include.
+ */
+ private boolean isEvaluatingContent() {
+ return this.xIncludeElementLevel == 0 ||
+ this.fallbackElementLevel > 0
+ && this.fallbackElementLevel == this.useFallbackLevel;
+ }
+
+ /**
+ *
+ * @return
+ */
+ private String getLocation() {
+ if (this.locator == null) {
+ return UNKNOWN_LOCATION;
+ } else {
+ return this.locator.getSystemId()
+ + ":"
+ + this.locator.getColumnNumber()
+ + ":"
+ + this.locator.getLineNumber();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void startDocument() throws SAXException {
+ if (this.xIncludeElementLevel == 0) {
+ this.getSAXConsumer().startDocument();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void endDocument() throws SAXException {
+ if (this.xIncludeElementLevel == 0) {
+ this.getSAXConsumer().endDocument();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void startElement(final String uri, final String localName, final String name, final Attributes atts)
+ throws SAXException {
+ if (XINCLUDE_NAMESPACE_URI.equals(uri)) {
+ // Handle xi:include:
+ if (XINCLUDE_INCLUDE.equals(localName)) {
+ // Process the include, unless in an ignored fallback:
+ if (this.isEvaluatingContent()) {
+ String href = atts.getValue("", XINCLUDE_HREF);
+
+ String parse = atts.getValue("", XINCLUDE_PARSE);
+ // Default for @parse is "xml"
+ if (parse == null) {
+ parse = XINCLUDE_PARSE_XML;
+ }
+
+ String xpointer = atts.getValue("", XINCLUDE_XPOINTER);
+ String encoding = atts.getValue("", XINCLUDE_ENCODING);
+
+ String accept = atts.getValue("", XINCLUDE_ACCEPT);
+ String acceptLanguage = atts.getValue("", XINCLUDE_ACCEPT_LANGUAGE);
+
+ this.processXIncludeElement(href, parse, xpointer, encoding, accept, acceptLanguage);
+ }
+ this.xIncludeElementLevel++;
+ } else if (XINCLUDE_FALLBACK.equals(localName)) {
+ // Handle xi:fallback
+ this.fallbackElementLevel++;
+ } else {
+ // Unknown element:
+ throw new SAXException("Unknown XInclude element " + localName + " at " + this.getLocation());
+ }
+ } else if (this.isEvaluatingContent()) {
+ // Copy other elements through when appropriate:
+ this.getSAXConsumer().startElement(uri, localName, name, atts);
+ }
+ }
+
+ /**
+ *
+ * @param href
+ * @param parse
+ * @param xpointer
+ * @param encoding
+ * @param accept
+ * @param acceptLanguage
+ * @throws SAXException
+ */
+ private void processXIncludeElement(String href, final String parse, String xpointer, String encoding,
+ final String accept, final String acceptLanguage) throws SAXException {
+ if (this.logger.isDebugEnabled()) {
+ this.logger.debug("Processing XInclude element: href="
+ + href
+ + ", parse="
+ + parse
+ + ", xpointer="
+ + xpointer
+ + ", encoding="
+ + encoding
+ + ", accept="
+ + accept
+ + ", acceptLanguage="
+ + acceptLanguage);
+ }
+
+ int fragmentIdentifierPos = href.indexOf('#');
+ if (fragmentIdentifierPos != -1) {
+ if (this.logger.isWarnEnabled()) {
+ this.logger.warn("Fragment identifer found in 'href' attribute: "
+ + href
+ + "\nFragment identifiers are forbidden by the XInclude specification. "
+ + "They are still handled by XIncludeTransformer for backward "
+ + "compatibility, but their use is deprecated and will be prohibited "
+ + "in a future release. Use the 'xpointer' attribute instead.");
+ }
+ if (xpointer == null) {
+ xpointer = href.substring(fragmentIdentifierPos + 1);
+ }
+ href = href.substring(0, fragmentIdentifierPos);
+ }
+
+ // An empty or absent href is a reference to the current document -- this can be different than the current base
+ if (!isNotEmpty(href)) {
+ throw new SAXException("XIncludeTransformer: encountered empty href (= href pointing to the current document).");
+ }
+ URL source = this.createSource(href);
+ URLConnection urlConnection = null;
+
+ try {
+ urlConnection = source.openConnection();
+ } catch (IOException ioe) {
+ this.useFallbackLevel++;
+ this.logger.error("Error including document: " + source, ioe);
+ }
+
+ if (urlConnection != null) {
+ if (this.logger.isDebugEnabled()) {
+ this.logger.debug("Parse type=" + parse);
+ }
+
+ if (XINCLUDE_PARSE_XML.equals(parse)) {
+ /* sends Accept and Accept-Language */
+ if (urlConnection instanceof HttpURLConnection) {
+ HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
+
+ if (isNotEmpty(accept)) {
+ httpURLConnection.setRequestProperty(HTTP_ACCEPT, accept);
+ }
+
+ if (isNotEmpty(acceptLanguage)) {
+ httpURLConnection.setRequestProperty(HTTP_ACCEPT_LANGUAGE, acceptLanguage);
+ }
+ }
+
+ if (xpointer != null && xpointer.length() > 0) {
+ try {
+ // create the context
+ XPointerContext xPointerContext = new XPointerContext(xpointer, this);
+ for (Entry<String, String> namespace : this.namespaces.entrySet()) {
+ xPointerContext.addPrefix(namespace.getKey(), namespace.getValue());
+ }
+
+ // initialize the XPointer handler by parsing the xpointer
+ XPointer xPointer = XPointerFrameworkParser.parse(xpointer);
+ xPointer.setLog(this.logger);
+
+ // setup components
+ xPointer.setUp(xPointerContext);
+ xPointer.setDocumentLocator(this.locator);
+
+ // go!
+ XMLUtils.toSax(urlConnection, xPointer);
+ } catch (ParseException e) {
+ // this exception is thrown in case of an invalid xpointer expression
+ this.useFallbackLevel++;
+ if (this.logger.isErrorEnabled()) {
+ this.logger.error("Error parsing XPointer expression, will try to use fallback.", e);
+ }
+ } catch (IOException e) {
+ this.useFallbackLevel++;
+ if (this.logger.isErrorEnabled()) {
+ this.logger.error("Error processing an xInclude, will try to use fallback.", e);
+ }
+ }
+ } else {
+ // just parse the whole document and stream it
+ XMLUtils.toSax(urlConnection, this);
+ }
+ } else if (XINCLUDE_PARSE_TEXT.equals(parse)) {
+ if (xpointer != null) {
+ throw new SAXException("xpointer attribute must not be present when parse='text': "
+ + this.getLocation());
+ }
+
+ // content type will be string like "text/xml; charset=UTF-8" or "text/xml"
+ String rawContentType = urlConnection.getContentType();
+
+ if (encoding == null) {
+ // text/xml and application/xml offer only one optional parameter
+ int index = rawContentType != null ? rawContentType.indexOf(';') : -1;
+
+ String charset = null;
+ if (index != -1) {
+ // this should be something like "charset=UTF-8", but we want to
+ // strip it down to just "UTF-8"
+ charset = rawContentType.substring(index + 1).trim();
+ if (charset.startsWith(CHARSET)) {
+ charset = charset.substring(CHARSET.length()).trim();
+ // strip quotes, if present
+ if (charset.charAt(0) == '"'
+ && charset.charAt(charset.length() - 1) == '"'
+ || charset.charAt(0) == '\''
+ && charset.charAt(charset.length() - 1)
+ == '\'') {
+ encoding =
+ charset.substring(1, charset.length() - 1);
+ }
+ } else {
+ encoding = DEFAULT_CHARSET;
+ }
+ } else {
+ encoding = DEFAULT_CHARSET;
+ }
+ }
+
+ InputStream is = null;
+ InputStreamReader isr = null;
+ Reader reader = null;
+
+ try {
+ is = urlConnection.getInputStream();
+ isr = new InputStreamReader(is, encoding);
+ reader = new BufferedReader(isr);
+
+ int read;
+ char ary[] = new char[1024 * 4];
+ while ((read = reader.read(ary)) != -1) {
+ this.getSAXConsumer().characters(ary, 0, read);
+ }
+ } catch (IOException e) {
+ this.useFallbackLevel++;
+ if (this.logger.isErrorEnabled()) {
+ this.logger.error("Error including text: ", e);
+ }
+ } finally {
+ closeQuietly(reader);
+ closeQuietly(isr);
+ closeQuietly(is);
+ }
+ } else {
+ throw new SAXException("Found 'parse' attribute with unknown value "
+ + parse
+ + " at "
+ + this.getLocation());
+ }
+ }
+ }
+
+ /**
+ *
+ * @param sourceAtt
+ * @return
+ */
+ private URL createSource(final String sourceAtt) {
+ try {
+ URL source = null;
+ if (sourceAtt.contains(":")) {
+ source = new URL(sourceAtt);
+ } else {
+ source = new URL(this.baseUrl, sourceAtt);
+ }
+ if (this.logger.isDebugEnabled()) {
+ this.logger.debug("Including source: " + source);
+ }
+
+ return source;
+ } catch (MalformedURLException e) {
+ String message = "Can't parse URL " + sourceAtt;
+ if (this.logger.isErrorEnabled()) {
+ this.logger.error(message, e);
+ }
+ throw new ProcessingException(message, e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void endElement(final String uri, final String localName, final String name) throws SAXException {
+ // Handle elements in xinclude namespace:
+ if (XINCLUDE_NAMESPACE_URI.equals(uri)) {
+ // Handle xi:include:
+ if (XINCLUDE_INCLUDE.equals(localName)) {
+ this.xIncludeElementLevel--;
+ if (this.useFallbackLevel > this.xIncludeElementLevel) {
+ this.useFallbackLevel = this.xIncludeElementLevel;
+ }
+ } else if (XINCLUDE_FALLBACK.equals(localName)) {
+ // Handle xi:fallback:
+ this.fallbackElementLevel--;
+ }
+ } else if (this.isEvaluatingContent()) {
+ // Copy other elements through when appropriate:
+ this.getSAXConsumer().endElement(uri, localName, name);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void startPrefixMapping(final String prefix, final String uri) throws SAXException {
+ if (this.isEvaluatingContent()) {
+ // removed xinclude namespace from result document
+ if (!uri.equals(XINCLUDE_NAMESPACE_URI)) {
+ this.getSAXConsumer().startPrefixMapping(prefix, uri);
+ }
+ this.namespaces.put(prefix, uri);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void endPrefixMapping(final String prefix) throws SAXException {
+ if (this.isEvaluatingContent()) {
+ this.getSAXConsumer().endPrefixMapping(prefix);
+ this.namespaces.remove(prefix);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void startCDATA() throws SAXException {
+ if (this.isEvaluatingContent()) {
+ this.getSAXConsumer().startCDATA();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void endCDATA() throws SAXException {
+ if (this.isEvaluatingContent()) {
+ this.getSAXConsumer().startCDATA();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void startDTD(final String name, final String publicId, final String systemId) throws SAXException {
+ // ignoring DTD
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void endDTD() throws SAXException {
+ // ignoring DTD
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void startEntity(final String name) throws SAXException {
+ if (this.isEvaluatingContent()) {
+ this.getSAXConsumer().startEntity(name);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void endEntity(final String name) throws SAXException {
+ if (this.isEvaluatingContent()) {
+ this.getSAXConsumer().endEntity(name);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void characters(final char[] ch, final int start, final int length) throws SAXException {
+ if (this.isEvaluatingContent()) {
+ this.getSAXConsumer().characters(ch, start, length);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void ignorableWhitespace(final char[] ch, final int start, final int length) throws SAXException {
+ if (this.isEvaluatingContent()) {
+ this.getSAXConsumer().ignorableWhitespace(ch, start, length);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void comment(final char[] ch, final int start, final int length) throws SAXException {
+ // skip comments
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void processingInstruction(final String target, final String data) throws SAXException {
+ if (this.isEvaluatingContent()) {
+ this.getSAXConsumer().processingInstruction(target, data);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setDocumentLocator(final Locator locator) {
+ if (this.logger.isDebugEnabled()) {
+ this.logger.debug("setDocumentLocator called "
+ + locator.getSystemId());
+ }
+
+ this.locator = locator;
+ this.getSAXConsumer().setDocumentLocator(locator);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void skippedEntity(final String name) throws SAXException {
+ if (this.isEvaluatingContent()) {
+ this.getSAXConsumer().skippedEntity(name);
+ }
+ }
+
+ private static boolean isNotEmpty(final String string) {
+ return string != null && string.length() > 0;
+ }
+
+ private static void closeQuietly(final Reader reader) {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (IOException e) {
+ // do nothing
+ }
+ }
+ }
+
+ private static void closeQuietly(final InputStream input) {
+ if (input != null) {
+ try {
+ input.close();
+ } catch (IOException e) {
+ // do nothing
+ }
+ }
+ }
+}
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/XIncludeTransformer.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/XIncludeTransformer.java
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/XIncludeTransformer.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/AbstractPointerPart.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/AbstractPointerPart.java?rev=892809&view=auto
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/AbstractPointerPart.java (added)
+++ cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/AbstractPointerPart.java Mon Dec 21 13:14:59 2009
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.sax.xpointer;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+
+/**
+ * $Id$
+ */
+abstract class AbstractPointerPart implements PointerPart {
+
+ public void characters(char[] ch, int start, int length) throws SAXException {
+ // do nothing as default behavior
+ }
+
+ public void endDocument() throws SAXException {
+ // do nothing as default behavior
+ }
+
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ // do nothing as default behavior
+ }
+
+ public void endPrefixMapping(String prefix) throws SAXException {
+ // do nothing as default behavior
+ }
+
+ public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
+ // do nothing as default behavior
+ }
+
+ public void processingInstruction(String target, String data) throws SAXException {
+ // do nothing as default behavior
+ }
+
+ public void setDocumentLocator(Locator locator) {
+ // do nothing as default behavior
+ }
+
+ public void skippedEntity(String name) throws SAXException {
+ // do nothing as default behavior
+ }
+
+ public void startDocument() throws SAXException {
+ // do nothing as default behavior
+ }
+
+ public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
+ // do nothing as default behavior
+ }
+
+ public void startPrefixMapping(String prefix, String uri) throws SAXException {
+ // do nothing as default behavior
+ }
+}
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/AbstractPointerPart.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/AbstractPointerPart.java
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/AbstractPointerPart.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/PointerPart.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/PointerPart.java?rev=892809&view=auto
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/PointerPart.java (added)
+++ cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/PointerPart.java Mon Dec 21 13:14:59 2009
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.sax.xpointer;
+
+import java.io.IOException;
+
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
+/**
+ * Interface to be implemented by pointer parts (xpointer schemes).
+ */
+public interface PointerPart extends ContentHandler {
+
+ /**
+ * If this pointer part successfully identifies any subresources, it should
+ * stream them to the XMLConsumer available from the XPointerContext and return true.
+ * Otherwise this method should return false.
+ */
+ void setUp(XPointerContext xpointerContext) throws SAXException, IOException;
+}
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/PointerPart.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/PointerPart.java
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/PointerPart.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/ShorthandPart.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/ShorthandPart.java?rev=892809&view=auto
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/ShorthandPart.java (added)
+++ cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/ShorthandPart.java Mon Dec 21 13:14:59 2009
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.sax.xpointer;
+
+import java.io.IOException;
+
+import org.apache.cocoon.sax.SAXConsumer;
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+
+/**
+ * Implements support for shorthand XPointers (= id-based lookup). We treat them here as if they
+ * were a pointerpart too.
+ *
+ * <p>Note that although this is implemented here, this feature depends on the presence of a DTD,
+ * and a validating parser. Currently, this means its unuseable within Cocoon.
+ *
+ * $Id$
+ */
+public final class ShorthandPart extends AbstractPointerPart {
+
+ private final static String XMLNS_NAMESPACE_98 = "http://www.w3.org/XML/1998/namespace";
+
+ private final static String XMLNS_NAMESPACE_00 = "http://www.w3.org/2000/xmlns/";
+
+ private final static String ID = "id";
+
+ private final String shorthand;
+
+ private SAXConsumer saxConsumer;
+
+ private boolean matching = false;
+
+ private int matchingLevel = 0;
+
+ public ShorthandPart(final String shorthand) {
+ this.shorthand = shorthand;
+ }
+
+ public void setUp(final XPointerContext xpointerContext) throws SAXException, IOException {
+ this.saxConsumer = xpointerContext.getSaxConsumer();
+ }
+
+ @Override
+ public void characters(char[] ch, int start, int length) throws SAXException {
+ if (this.matching) {
+ this.saxConsumer.characters(ch, start, length);
+ }
+ }
+
+ @Override
+ public void endDocument() throws SAXException {
+ this.saxConsumer.endDocument();
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ if (this.matching) {
+ this.saxConsumer.endElement(uri, localName, qName);
+ this.matchingLevel--;
+
+ if (this.matchingLevel == 0) {
+ this.matching = false;
+ }
+ }
+ }
+
+ @Override
+ public void endPrefixMapping(String prefix) throws SAXException {
+ if (this.matching) {
+ this.saxConsumer.endPrefixMapping(prefix);
+ }
+ }
+
+ @Override
+ public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
+ if (this.matching) {
+ this.saxConsumer.ignorableWhitespace(ch, start, length);
+ }
+ }
+
+ @Override
+ public void processingInstruction(String target, String data) throws SAXException {
+ if (this.matching) {
+ this.saxConsumer.processingInstruction(target, data);
+ }
+ }
+
+ @Override
+ public void setDocumentLocator(Locator locator) {
+ // ignored, already set on the sax consumer
+ }
+
+ @Override
+ public void skippedEntity(String name) throws SAXException {
+ if (this.matching) {
+ this.saxConsumer.skippedEntity(name);
+ }
+ }
+
+ @Override
+ public void startDocument() throws SAXException {
+ this.saxConsumer.startDocument();
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
+ if (!this.matching) {
+ dance: for (int i = 0; i < atts.getLength(); i++) {
+ String attributeURI = atts.getURI(i);
+ String attributeName = atts.getLocalName(i);
+ String attributeValue = atts.getValue(i);
+
+ if ((attributeURI == null
+ || attributeURI.length() == 0
+ || XMLNS_NAMESPACE_98.equals(attributeURI)
+ || XMLNS_NAMESPACE_00.equals(attributeURI))
+ && ID.equalsIgnoreCase(attributeName)
+ && this.shorthand.equals(attributeValue)) {
+ this.matching = true;
+ this.matchingLevel = 0;
+
+ break dance;
+ }
+ }
+ }
+
+ if (this.matching) {
+ this.saxConsumer.startElement(uri, localName, qName, atts);
+ this.matchingLevel++;
+ }
+ }
+
+ @Override
+ public void startPrefixMapping(String prefix, String uri) throws SAXException {
+ if (this.matching) {
+ this.saxConsumer.startPrefixMapping(prefix, uri);
+ }
+ }
+}
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/ShorthandPart.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/ShorthandPart.java
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/ShorthandPart.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/TransformerHandlerFactory.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/TransformerHandlerFactory.java?rev=892809&view=auto
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/TransformerHandlerFactory.java (added)
+++ cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/TransformerHandlerFactory.java Mon Dec 21 13:14:59 2009
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.sax.xpointer;
+
+import java.io.StringReader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.Templates;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+import javax.xml.transform.stream.StreamSource;
+
+import org.xml.sax.ContentHandler;
+
+/**
+ * $Id$
+ */
+final class TransformerHandlerFactory {
+
+ /**
+ * A generic transformer factory to parse XSLTs.
+ */
+ private static final SAXTransformerFactory TRAX_FACTORY = (SAXTransformerFactory) TransformerFactory.newInstance();
+
+ private static final String XMLNS_PATTERN = "xmlns:%s=\"%s\"";
+
+ private static final String XSLT_PATTERN =
+ "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" %s>"
+ + "<xsl:template match=\"%s\">"
+ + "<xsl:copy-of select=\".\"/>"
+ + "</xsl:template></xsl:stylesheet>";
+
+ private static final Map<String, Templates> TEMPLATES = new HashMap<String, Templates>();
+
+ /**
+ * This class can't be instantiated
+ */
+ private TransformerHandlerFactory() {
+ // do nothing
+ }
+
+ public static TransformerHandler borrowHandler(final Map<String, String> namespaces,
+ final String expression,
+ final ContentHandler delegate) throws TransformerConfigurationException {
+ Templates templates = null;
+ if (TEMPLATES.containsKey(expression)) {
+ templates = TEMPLATES.get(expression);
+ } else {
+ StringBuilder builder = new StringBuilder();
+ for (Entry<String, String> namespace : namespaces.entrySet()) {
+ builder.append('\n');
+ builder.append(String.format(XMLNS_PATTERN, namespace.getKey(), namespace.getValue()));
+ }
+ String xmlNamespaces = builder.toString();
+
+ String xslt = String.format(XSLT_PATTERN, xmlNamespaces, expression);
+ Source source = new StreamSource(new StringReader(xslt));
+ templates = TRAX_FACTORY.newTemplates(source);
+ TEMPLATES.put(expression, templates);
+ }
+
+ final SAXResult result = new SAXResult();
+ result.setHandler(delegate);
+
+ TransformerHandler transformerHandler = TRAX_FACTORY.newTransformerHandler(templates);
+ transformerHandler.setResult(result);
+ return transformerHandler;
+ }
+}
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/TransformerHandlerFactory.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/TransformerHandlerFactory.java
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/TransformerHandlerFactory.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/UnsupportedPart.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/UnsupportedPart.java?rev=892809&view=auto
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/UnsupportedPart.java (added)
+++ cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/UnsupportedPart.java Mon Dec 21 13:14:59 2009
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.sax.xpointer;
+
+import java.io.IOException;
+
+import org.xml.sax.SAXException;
+
+/**
+ * $Id$
+ */
+public final class UnsupportedPart extends AbstractPointerPart {
+
+ private String schemeName;
+
+ public UnsupportedPart(final String schemeName) {
+ this.schemeName = schemeName;
+ }
+
+ public void setUp(final XPointerContext xpointerContext) throws SAXException, IOException {
+ throw new SAXException("Scheme '"
+ + this.schemeName
+ + "' not supported by this XPointer implementation, as used in the fragment identifier '"
+ + xpointerContext.getXPointer()
+ + "'");
+ }
+}
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/UnsupportedPart.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/UnsupportedPart.java
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/UnsupportedPart.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointer.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointer.java?rev=892809&view=auto
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointer.java (added)
+++ cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointer.java Mon Dec 21 13:14:59 2009
@@ -0,0 +1,177 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.sax.xpointer;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+
+/**
+ * $Id$
+ */
+public final class XPointer implements ContentHandler {
+
+ private final List<PointerPart> pointerParts = new ArrayList<PointerPart>();
+
+ private Log log;
+
+ public void setLog(Log log) {
+ this.log = log;
+ }
+
+ public void addPart(final PointerPart part) {
+ this.pointerParts.add(part);
+ }
+
+ public void setUp(final XPointerContext xpointerContext) throws SAXException, IOException {
+ for (PointerPart pointerPart : this.pointerParts) {
+ pointerPart.setUp(xpointerContext);
+ }
+ }
+
+ public void characters(char[] ch, int start, int length) throws SAXException {
+ for (ContentHandler contentHandler : this.pointerParts) {
+ try {
+ contentHandler.characters(ch, start, length);
+ } catch (SAXException e) {
+ if (this.log.isWarnEnabled()) {
+ this.log.warn("An error occurred while spreading characters", e);
+ }
+ }
+ }
+ }
+
+ public void endDocument() throws SAXException {
+ for (ContentHandler contentHandler : this.pointerParts) {
+ try {
+ contentHandler.endDocument();
+ } catch (SAXException e) {
+ if (this.log.isWarnEnabled()) {
+ this.log.warn("An error occurred while spreading endDocument", e);
+ }
+ }
+ }
+ }
+
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ for (ContentHandler contentHandler : this.pointerParts) {
+ try {
+ contentHandler.endElement(uri, localName, qName);
+ } catch (SAXException e) {
+ if (this.log.isWarnEnabled()) {
+ this.log.warn("An error occurred while spreading endElement", e);
+ }
+ }
+ }
+ }
+
+ public void endPrefixMapping(String prefix) throws SAXException {
+ for (ContentHandler contentHandler : this.pointerParts) {
+ try {
+ contentHandler.endPrefixMapping(prefix);
+ } catch (SAXException e) {
+ if (this.log.isWarnEnabled()) {
+ this.log.warn("An error occurred while spreading endPrefixMapping", e);
+ }
+ }
+ }
+ }
+
+ public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
+ for (ContentHandler contentHandler : this.pointerParts) {
+ try {
+ contentHandler.ignorableWhitespace(ch, start, length);
+ } catch (SAXException e) {
+ if (this.log.isWarnEnabled()) {
+ this.log.warn("An error occurred while spreading ignorableWhitespace", e);
+ }
+ }
+ }
+ }
+
+ public void processingInstruction(String target, String data) throws SAXException {
+ for (ContentHandler contentHandler : this.pointerParts) {
+ try {
+ contentHandler.processingInstruction(target, data);
+ } catch (SAXException e) {
+ if (this.log.isWarnEnabled()) {
+ this.log.warn("An error occurred while spreading processingInstruction", e);
+ }
+ }
+ }
+ }
+
+ public void setDocumentLocator(Locator locator) {
+ for (ContentHandler contentHandler : this.pointerParts) {
+ contentHandler.setDocumentLocator(locator);
+ }
+ }
+
+ public void skippedEntity(String name) throws SAXException {
+ for (ContentHandler contentHandler : this.pointerParts) {
+ try {
+ contentHandler.skippedEntity(name);
+ } catch (SAXException e) {
+ if (this.log.isWarnEnabled()) {
+ this.log.warn("An error occurred while spreading skippedEntity", e);
+ }
+ }
+ }
+ }
+
+ public void startDocument() throws SAXException {
+ for (ContentHandler contentHandler : this.pointerParts) {
+ try {
+ contentHandler.startDocument();
+ } catch (SAXException e) {
+ if (this.log.isWarnEnabled()) {
+ this.log.warn("An error occurred while spreading skippedEntity", e);
+ }
+ }
+ }
+ }
+
+ public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
+ for (ContentHandler contentHandler : this.pointerParts) {
+ try {
+ contentHandler.startElement(uri, localName, qName, atts);
+ } catch (SAXException e) {
+ if (this.log.isWarnEnabled()) {
+ this.log.warn("An error occurred while spreading skippedEntity", e);
+ }
+ }
+ }
+ }
+
+ public void startPrefixMapping(String prefix, String uri) throws SAXException {
+ for (ContentHandler contentHandler : this.pointerParts) {
+ try {
+ contentHandler.startPrefixMapping(prefix, uri);
+ } catch (SAXException e) {
+ if (this.log.isWarnEnabled()) {
+ this.log.warn("An error occurred while spreading skippedEntity", e);
+ }
+ }
+ }
+ }
+}
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointer.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointer.java
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointer.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointerContext.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointerContext.java?rev=892809&view=auto
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointerContext.java (added)
+++ cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointerContext.java Mon Dec 21 13:14:59 2009
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.sax.xpointer;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.xml.namespace.NamespaceContext;
+
+import org.apache.cocoon.sax.SAXConsumer;
+
+/**
+ * $Id$
+ */
+public final class XPointerContext implements NamespaceContext {
+
+ private final static String XML_NAMESPACE = "http://www.w3.org/XML/1998/namespace";
+
+ private final static String XMLNS_NAMESPACE = "http://www.w3.org/2000/xmlns/";
+
+ private final static String XSL_NAMESPACE = "http://www.w3.org/1999/XSL/Transform";
+
+ private final Map<String, String> namespaces = new HashMap<String, String>();
+
+ private final String xPointer;
+
+ private final SAXConsumer saxConsumer;
+
+ public XPointerContext(final String xPointer, final SAXConsumer saxConsumer) {
+ this.xPointer = xPointer;
+ this.saxConsumer = saxConsumer;
+ }
+
+ public String getXPointer() {
+ return this.xPointer;
+ }
+
+ public SAXConsumer getSaxConsumer() {
+ return this.saxConsumer;
+ }
+
+ public Map<String, String> getNamespaces() {
+ return this.namespaces;
+ }
+
+ public void addPrefix(final String prefix, final String namespaceURI) {
+ if (XML_NAMESPACE.equals(namespaceURI)
+ || XMLNS_NAMESPACE.equals(namespaceURI)
+ || XSL_NAMESPACE.equals(namespaceURI)) {
+ return;
+ }
+
+ this.namespaces.put(prefix, namespaceURI);
+ }
+
+ // This method isn't necessary for XPath processing either.
+ public String getPrefix(String namespaceURI) {
+ throw new UnsupportedOperationException();
+ }
+
+ @SuppressWarnings("unchecked")
+ // This method isn't necessary for XPath processing either.
+ public Iterator getPrefixes(final String namespaceURI) {
+ throw new UnsupportedOperationException();
+ }
+
+ // This method isn't necessary for XPath processing either.
+ public String getNamespaceURI(final String prefix) {
+ return this.namespaces.get(prefix);
+ }
+}
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointerContext.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointerContext.java
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointerContext.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointerPart.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointerPart.java?rev=892809&view=auto
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointerPart.java (added)
+++ cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointerPart.java Mon Dec 21 13:14:59 2009
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.sax.xpointer;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.Templates;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+import javax.xml.transform.stream.StreamSource;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+
+/**
+ * $Id$
+ */
+public final class XPointerPart extends AbstractPointerPart {
+
+ /**
+ * A generic transformer factory to parse XSLTs.
+ */
+ private static final SAXTransformerFactory TRAX_FACTORY = (SAXTransformerFactory) TransformerFactory.newInstance();
+
+ private static final String XMLNS_PATTERN = "xmlns:%s=\"%s\"";
+
+ private static final String XSLT_PATTERN =
+ "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" %s>"
+ + "<xsl:template match=\"%s\">"
+ + "<xsl:copy-of select=\".\"/>"
+ + "</xsl:template></xsl:stylesheet>";
+
+ private static final Map<String, Templates> TEMPLATES = new HashMap<String, Templates>();
+
+ private final String expression;
+
+ private TransformerHandler traxHandler;
+
+ public XPointerPart(final String expression) {
+ this.expression = expression;
+ }
+
+ public void setUp(final XPointerContext xpointerContext) throws SAXException, IOException {
+ Templates templates;
+ if (TEMPLATES.containsKey(this.expression)) {
+ templates = TEMPLATES.get(this.expression);
+ } else {
+ StringBuilder builder = new StringBuilder();
+ for (Entry<String, String> namespace : xpointerContext.getNamespaces().entrySet()) {
+ builder.append('\n');
+ builder.append(String.format(XMLNS_PATTERN, namespace.getKey(), namespace.getValue()));
+ }
+ String xmlNamespaces = builder.toString();
+
+ String xslt = String.format(XSLT_PATTERN, xmlNamespaces, this.expression);
+ Source source = new StreamSource(new StringReader(xslt));
+ try {
+ templates = TRAX_FACTORY.newTemplates(source);
+ } catch (TransformerConfigurationException tce) {
+ throw new SAXException("XPointer expression '"
+ + this.expression
+ + "' not valid as used in the fragment identifier '"
+ + xpointerContext.getXPointer()
+ + "'", tce);
+ }
+ TEMPLATES.put(this.expression, templates);
+ }
+
+ final SAXResult result = new SAXResult();
+ result.setHandler(xpointerContext.getSaxConsumer());
+
+ try {
+ this.traxHandler = TRAX_FACTORY.newTransformerHandler(templates);
+ this.traxHandler.setResult(result);
+ } catch (TransformerConfigurationException tce) {
+ throw new SAXException("Impossible to initialize transformer handler for XPointer expression '"
+ + this.expression
+ + "' as used in the fragment identifier '"
+ + xpointerContext.getXPointer()
+ + "'", tce);
+ }
+ }
+
+ @Override
+ public void characters(char[] ch, int start, int length) throws SAXException {
+ this.traxHandler.characters(ch, start, length);
+ }
+
+ @Override
+ public void endDocument() throws SAXException {
+ this.traxHandler.endDocument();
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ this.traxHandler.endElement(uri, localName, qName);
+ }
+
+ @Override
+ public void endPrefixMapping(String prefix) throws SAXException {
+ this.traxHandler.endPrefixMapping(prefix);
+ }
+
+ @Override
+ public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
+ this.traxHandler.ignorableWhitespace(ch, start, length);
+ }
+
+ @Override
+ public void processingInstruction(String target, String data) throws SAXException {
+ this.traxHandler.processingInstruction(target, data);
+ }
+
+ @Override
+ public void setDocumentLocator(Locator locator) {
+ this.traxHandler.setDocumentLocator(locator);
+ }
+
+ @Override
+ public void skippedEntity(String name) throws SAXException {
+ this.traxHandler.skippedEntity(name);
+ }
+
+ @Override
+ public void startDocument() throws SAXException {
+ this.traxHandler.startDocument();
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
+ this.traxHandler.startElement(uri, localName, qName, atts);
+ }
+
+ @Override
+ public void startPrefixMapping(String prefix, String uri) throws SAXException {
+ this.traxHandler.startPrefixMapping(prefix, uri);
+ }
+}
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointerPart.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointerPart.java
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XPointerPart.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XmlnsPart.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XmlnsPart.java?rev=892809&view=auto
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XmlnsPart.java (added)
+++ cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XmlnsPart.java Mon Dec 21 13:14:59 2009
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.sax.xpointer;
+
+import java.io.IOException;
+
+import org.xml.sax.SAXException;
+
+/**
+ * $Id$
+ */
+public final class XmlnsPart extends AbstractPointerPart {
+
+ private String prefix;
+
+ private String namespace;
+
+ /**
+ * Creates an XmlnsPart.
+ */
+ public XmlnsPart(final String prefix, final String namespace) {
+ this.prefix = prefix;
+ this.namespace = namespace;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setUp(final XPointerContext xpointerContext) throws SAXException, IOException {
+ xpointerContext.addPrefix(this.prefix, this.namespace);
+ }
+}
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XmlnsPart.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XmlnsPart.java
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/xpointer/XmlnsPart.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: cocoon/cocoon3/trunk/cocoon-sax/src/main/javacc/xpointer-fw.jj
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sax/src/main/javacc/xpointer-fw.jj?rev=892809&view=auto
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sax/src/main/javacc/xpointer-fw.jj (added)
+++ cocoon/cocoon3/trunk/cocoon-sax/src/main/javacc/xpointer-fw.jj Mon Dec 21 13:14:59 2009
@@ -0,0 +1,309 @@
+options {
+ STATIC = false;
+}
+
+PARSER_BEGIN(XPointerFrameworkParser)
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.sax.xpointer;
+
+import java.io.StringReader;
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * Parser for the XPointer Framework Syntax, see the specification at:
+ * http://www.w3.org/TR/2003/REC-xptr-framework-20030325/
+ *
+ * Some of the token definitions (for recognizing NCName's) were copied from
+ * the JXPath parser from Apache Commons (to save some typing), written by
+ * Ingo Macherius, Gerald Huck <{macherius, huck}@gmd.de> and Dmitri Plotnikov.
+ *
+ * $Id$
+ */
+public class XPointerFrameworkParser {
+
+ private static final String XPOINTER = "xpointer";
+
+ private static final String XMLNS = "xmlns";
+
+ private XPointer xpointer = new XPointer();
+
+ private Map<String, String> namespaces = new HashMap<String, String>();
+
+ public static XPointer parse(final String xpointer) throws ParseException {
+ XPointerFrameworkParser xfp = new XPointerFrameworkParser(new StringReader(xpointer));
+ xfp.pointer();
+ return xfp.getXPointer();
+ }
+
+ public XPointer getXPointer() {
+ return this.xpointer;
+ }
+
+ private String unescape(final String data) throws ParseException {
+ StringBuilder result = new StringBuilder(data.length());
+ boolean inCircumflex = false;
+ for (int i = 0; i < data.length(); i++) {
+ char c = data.charAt(i);
+ if (inCircumflex) {
+ switch (c) {
+ case '^':
+ case '(':
+ case ')':
+ result.append(c);
+ inCircumflex = false;
+ break;
+
+ default:
+ throw new ParseException("Incorrect use of circumflex character at position "
+ + i
+ + " in the string "
+ + data);
+ }
+ } else if (c == '^') {
+ inCircumflex = true;
+ } else {
+ result.append(c);
+ }
+ }
+ return result.toString();
+ }
+
+}
+
+PARSER_END(XPointerFrameworkParser)
+
+TOKEN :
+{
+ <#Letter : <BaseChar> | <Ideographic> >
+| <#BaseChar :
+ (
+ ["\u0041"-"\u005A"] | ["\u0061"-"\u007A"] | ["\u00C0"-"\u00D6"] | ["\u00D8"-"\u00F6"] |
+ ["\u00F8"-"\u00FF"] | ["\u0100"-"\u0131"] | ["\u0134"-"\u013E"] | ["\u0141"-"\u0148"] |
+ ["\u014A"-"\u017E"] | ["\u0180"-"\u01C3"] | ["\u01CD"-"\u01F0"] | ["\u01F4"-"\u01F5"] |
+ ["\u01FA"-"\u0217"] | ["\u0250"-"\u02A8"] | ["\u02BB"-"\u02C1"] | "\u0386" | ["\u0388"-"\u038A"] |
+ "\u038C" | ["\u038E"-"\u03A1"] | ["\u03A3"-"\u03CE"] | ["\u03D0"-"\u03D6"] | "\u03DA" |
+ "\u03DC" | "\u03DE" | "\u03E0" | ["\u03E2"-"\u03F3"] | ["\u0401"-"\u040C"] | ["\u040E"-"\u044F"] |
+ ["\u0451"-"\u045C"] | ["\u045E"-"\u0481"] | ["\u0490"-"\u04C4"] | ["\u04C7"-"\u04C8"] |
+ ["\u04CB"-"\u04CC"] | ["\u04D0"-"\u04EB"] | ["\u04EE"-"\u04F5"] | ["\u04F8"-"\u04F9"] |
+ ["\u0531"-"\u0556"] | "\u0559" | ["\u0561"-"\u0586"] | ["\u05D0"-"\u05EA"] | ["\u05F0"-"\u05F2"] |
+ ["\u0621"-"\u063A"] | ["\u0641"-"\u064A"] | ["\u0671"-"\u06B7"] | ["\u06BA"-"\u06BE"] |
+ ["\u06C0"-"\u06CE"] | ["\u06D0"-"\u06D3"] | "\u06D5" | ["\u06E5"-"\u06E6"] | ["\u0905"-"\u0939"] |
+ "\u093D" | ["\u0958"-"\u0961"] | ["\u0985"-"\u098C"] | ["\u098F"-"\u0990"] | ["\u0993"-"\u09A8"] |
+ ["\u09AA"-"\u09B0"] | "\u09B2" | ["\u09B6"-"\u09B9"] | ["\u09DC"-"\u09DD"] | ["\u09DF"-"\u09E1"] |
+ ["\u09F0"-"\u09F1"] | ["\u0A05"-"\u0A0A"] | ["\u0A0F"-"\u0A10"] | ["\u0A13"-"\u0A28"] |
+ ["\u0A2A"-"\u0A30"] | ["\u0A32"-"\u0A33"] | ["\u0A35"-"\u0A36"] | ["\u0A38"-"\u0A39"] |
+ ["\u0A59"-"\u0A5C"] | "\u0A5E" | ["\u0A72"-"\u0A74"] | ["\u0A85"-"\u0A8B"] | "\u0A8D" |
+ ["\u0A8F"-"\u0A91"] | ["\u0A93"-"\u0AA8"] | ["\u0AAA"-"\u0AB0"] | ["\u0AB2"-"\u0AB3"] |
+ ["\u0AB5"-"\u0AB9"] | "\u0ABD" | "\u0AE0" | ["\u0B05"-"\u0B0C"] | ["\u0B0F"-"\u0B10"] |
+ ["\u0B13"-"\u0B28"] | ["\u0B2A"-"\u0B30"] | ["\u0B32"-"\u0B33"] | ["\u0B36"-"\u0B39"] |
+ "\u0B3D" | ["\u0B5C"-"\u0B5D"] | ["\u0B5F"-"\u0B61"] | ["\u0B85"-"\u0B8A"] | ["\u0B8E"-"\u0B90"] |
+ ["\u0B92"-"\u0B95"] | ["\u0B99"-"\u0B9A"] | "\u0B9C" | ["\u0B9E"-"\u0B9F"] | ["\u0BA3"-"\u0BA4"] |
+ ["\u0BA8"-"\u0BAA"] | ["\u0BAE"-"\u0BB5"] | ["\u0BB7"-"\u0BB9"] | ["\u0C05"-"\u0C0C"] |
+ ["\u0C0E"-"\u0C10"] | ["\u0C12"-"\u0C28"] | ["\u0C2A"-"\u0C33"] | ["\u0C35"-"\u0C39"] |
+ ["\u0C60"-"\u0C61"] | ["\u0C85"-"\u0C8C"] | ["\u0C8E"-"\u0C90"] | ["\u0C92"-"\u0CA8"] |
+ ["\u0CAA"-"\u0CB3"] | ["\u0CB5"-"\u0CB9"] | "\u0CDE" | ["\u0CE0"-"\u0CE1"] | ["\u0D05"-"\u0D0C"] |
+ ["\u0D0E"-"\u0D10"] | ["\u0D12"-"\u0D28"] | ["\u0D2A"-"\u0D39"] | ["\u0D60"-"\u0D61"] |
+ ["\u0E01"-"\u0E2E"] | "\u0E30" | ["\u0E32"-"\u0E33"] | ["\u0E40"-"\u0E45"] | ["\u0E81"-"\u0E82"] |
+ "\u0E84" | ["\u0E87"-"\u0E88"] | "\u0E8A" | "\u0E8D" | ["\u0E94"-"\u0E97"] | ["\u0E99"-"\u0E9F"] |
+ ["\u0EA1"-"\u0EA3"] | "\u0EA5" | "\u0EA7" | ["\u0EAA"-"\u0EAB"] | ["\u0EAD"-"\u0EAE"] | "\u0EB0" |
+ ["\u0EB2"-"\u0EB3"] | "\u0EBD" | ["\u0EC0"-"\u0EC4"] | ["\u0F40"-"\u0F47"] | ["\u0F49"-"\u0F69"] |
+ ["\u10A0"-"\u10C5"] | ["\u10D0"-"\u10F6"] | "\u1100" | ["\u1102"-"\u1103"] | ["\u1105"-"\u1107"] |
+ "\u1109" | ["\u110B"-"\u110C"] | ["\u110E"-"\u1112"] | "\u113C" | "\u113E" | "\u1140" | "\u114C" |
+ "\u114E" | "\u1150" | ["\u1154"-"\u1155"] | "\u1159" | ["\u115F"-"\u1161"] | "\u1163" | "\u1165" |
+ "\u1167" | "\u1169" | ["\u116D"-"\u116E"] | ["\u1172"-"\u1173"] | "\u1175" | "\u119E" | "\u11A8" |
+ "\u11AB" | ["\u11AE"-"\u11AF"] | ["\u11B7"-"\u11B8"] | "\u11BA" | ["\u11BC"-"\u11C2"] | "\u11EB" |
+ "\u11F0" | "\u11F9" | ["\u1E00"-"\u1E9B"] | ["\u1EA0"-"\u1EF9"] | ["\u1F00"-"\u1F15"] |
+ ["\u1F18"-"\u1F1D"] |
+ ["\u1F20"-"\u1F45"] | ["\u1F48"-"\u1F4D"] | ["\u1F50"-"\u1F57"] | "\u1F59" | "\u1F5B" | "\u1F5D" |
+ ["\u1F5F"-"\u1F7D"] | ["\u1F80"-"\u1FB4"] | ["\u1FB6"-"\u1FBC"] | "\u1FBE" | ["\u1FC2"-"\u1FC4"] |
+ ["\u1FC6"-"\u1FCC"] | ["\u1FD0"-"\u1FD3"] | ["\u1FD6"-"\u1FDB"] | ["\u1FE0"-"\u1FEC"] |
+ ["\u1FF2"-"\u1FF4"] | ["\u1FF6"-"\u1FFC"] | "\u2126" | ["\u212A"-"\u212B"] | "\u212E" |
+ ["\u2180"-"\u2182"] | ["\u3041"-"\u3094"] | ["\u30A1"-"\u30FA"] | ["\u3105"-"\u312C"] |
+ ["\uAC00"-"\uD7A3"]
+ ) >
+| <#Ideographic : (["\u4E00"-"\u9FA5"] | "\u3007" | ["\u3021"-"\u3029"]) >
+| <#CombiningChar :
+ (
+ ["\u0300"-"\u0345"] | ["\u0360"-"\u0361"] | ["\u0483"-"\u0486"] | ["\u0591"-"\u05A1"] |
+ ["\u05A3"-"\u05B9"] | ["\u05BB"-"\u05BD"] | "\u05BF" | ["\u05C1"-"\u05C2"] |
+ "\u05C4" | ["\u064B"-"\u0652"] | "\u0670" | ["\u06D6"-"\u06DC"] |
+ ["\u06DD"-"\u06DF"] | ["\u06E0"-"\u06E4"] | ["\u06E7"-"\u06E8"] | ["\u06EA"-"\u06ED"] |
+ ["\u0901"-"\u0903"] | "\u093C" |["\u093E"-"\u094C"] | "\u094D" | ["\u0951"-"\u0954"] |
+ ["\u0962"-"\u0963"] | ["\u0981"-"\u0983"] | "\u09BC" | "\u09BE" | "\u09BF" | ["\u09C0"-"\u09C4"] |
+ ["\u09C7"-"\u09C8"] | ["\u09CB"-"\u09CD"] | "\u09D7" | ["\u09E2"-"\u09E3"] | "\u0A02" | "\u0A3C" |
+ "\u0A3E" | "\u0A3F" | ["\u0A40"-"\u0A42"] |
+ ["\u0A47"-"\u0A48"] | ["\u0A4B"-"\u0A4D"] | ["\u0A70"-"\u0A71"] | ["\u0A81"-"\u0A83"] | "\u0ABC" |
+ ["\u0ABE"-"\u0AC5"] | ["\u0AC7"-"\u0AC9"] | ["\u0ACB"-"\u0ACD"] | ["\u0B01"-"\u0B03"] | "\u0B3C" |
+ ["\u0B3E"-"\u0B43"] | ["\u0B47"-"\u0B48"] | ["\u0B4B"-"\u0B4D"] | ["\u0B56"-"\u0B57"] |
+ ["\u0B82"-"\u0B83"] | ["\u0BBE"-"\u0BC2"] | ["\u0BC6"-"\u0BC8"] | ["\u0BCA"-"\u0BCD"] | "\u0BD7" |
+ ["\u0C01"-"\u0C03"] | ["\u0C3E"-"\u0C44"] | ["\u0C46"-"\u0C48"] | ["\u0C4A"-"\u0C4D"] |
+ ["\u0C55"-"\u0C56"] | ["\u0C82"-"\u0C83"] | ["\u0CBE"-"\u0CC4"] | ["\u0CC6"-"\u0CC8"] |
+ ["\u0CCA"-"\u0CCD"] | ["\u0CD5"-"\u0CD6"] | ["\u0D02"-"\u0D03"] | ["\u0D3E"-"\u0D43"] |
+ ["\u0D46"-"\u0D48"] | ["\u0D4A"-"\u0D4D"] | "\u0D57" | "\u0E31" | ["\u0E34"-"\u0E3A"] |
+ ["\u0E47"-"\u0E4E"] | "\u0EB1" | ["\u0EB4"-"\u0EB9"] | ["\u0EBB"-"\u0EBC"] | ["\u0EC8"-"\u0ECD"] |
+ ["\u0F18"-"\u0F19"] | "\u0F35" | "\u0F37" | "\u0F39" | "\u0F3E" | "\u0F3F" | ["\u0F71"-"\u0F84"] |
+ ["\u0F86"-"\u0F8B"] | ["\u0F90"-"\u0F95"] | "\u0F97" | ["\u0F99"-"\u0FAD"] | ["\u0FB1"-"\u0FB7"] |
+ "\u0FB9" | ["\u20D0"-"\u20DC"] | "\u20E1" | ["\u302A"-"\u302F"] | "\u3099" | "\u309A"
+ )
+ >
+| <#UnicodeDigit :
+ ["\u0030"-"\u0039"] | ["\u0660"-"\u0669"] | ["\u06F0"-"\u06F9"] | ["\u0966"-"\u096F"] |
+ ["\u09E6"-"\u09EF"] | ["\u0A66"-"\u0A6F"] | ["\u0AE6"-"\u0AEF"] | ["\u0B66"-"\u0B6F"] |
+ ["\u0BE7"-"\u0BEF"] | ["\u0C66"-"\u0C6F"] | ["\u0CE6"-"\u0CEF"] | ["\u0D66"-"\u0D6F"] |
+ ["\u0E50"-"\u0E59"] | ["\u0ED0"-"\u0ED9"] | ["\u0F20"-"\u0F29"]
+ >
+| <#Extender :
+ "\u00B7" | "\u02D0" | "\u02D1" | "\u0387" | "\u0640" | "\u0E46" | "\u0EC6" |
+ "\u3005" | ["\u3031"-"\u3035"] | ["\u309D"-"\u309E"] | ["\u30FC"-"\u30FE"]
+ >
+| <NCName : (<Letter> | ["_"]) (<Letter> | <UnicodeDigit> | [".","-","_"] | <CombiningChar> | <Extender>)* >
+| <WS: ["\t", "\r", "\n", " "] >
+| <QName : (<NCName> ":")? <NCName> >
+}
+
+<DEFAULT, IN_SCHEME>
+TOKEN :
+{
+ <LBRACE: "(" >
+| <RBRACE: ")" >
+}
+
+<IN_SCHEME>
+TOKEN :
+{
+ <CIRC_LBRACE: "^(" >
+| <CIRC_RBRACE: "^)" >
+| <DOUBLE_CIRC: "^^" >
+| <NormalChar: ~["(", ")", "^"] >
+}
+
+void pointer():
+{
+}
+{
+ LOOKAHEAD(2) schemeBased() | shortHand()
+}
+
+void shortHand():
+{
+ Token x;
+}
+{
+ x = <NCName>
+ {
+ xpointer.addPart(new ShorthandPart(x.image));
+ }
+}
+
+void schemeBased():
+{
+}
+{
+ pointerPart() ( (<WS>)* pointerPart() )*
+}
+
+void pointerPart():
+{
+ Token x;
+ String schemeName;
+ String schemeData;
+}
+{
+ (x = <NCName> | x = <QName>)
+ <LBRACE>
+ {
+ // when going inside the scheme data, swith to a different lexical state
+ token_source.SwitchTo(IN_SCHEME);
+
+ // store the scheme name
+ schemeName = x.image;
+ }
+ schemeData = schemeData()
+ <RBRACE>
+ {
+ // when going outside the scheme data, swith back to the default lexical state
+ token_source.SwitchTo(DEFAULT);
+
+ // parse schemeName in prefix and localName
+ String schemeNamespace = null, schemeLocalName = null;
+ int colonPos = schemeName.indexOf(':');
+ if (colonPos != -1) {
+ String schemePrefix = schemeName.substring(0, colonPos);
+ schemeNamespace = (String) namespaces.get(schemePrefix);
+ schemeLocalName = schemeName.substring(colonPos + 1);
+ } else {
+ schemeLocalName = schemeName;
+ }
+
+ // add the pointer part
+ if (schemeNamespace == null && XMLNS.equals(schemeLocalName)) {
+ int eqPos = schemeData.indexOf("=");
+ if (eqPos == -1) {
+ throw new ParseException("xmlns scheme data should contain an equals sign");
+ }
+
+ // Note: the trimming below is not entirely correct, since space is only allowed left
+ // and right of the equal sign, but not at the beginning and end of the schemeData
+ String prefix = schemeData.substring(0, eqPos).trim();
+ String namespace = schemeData.substring(eqPos + 1, schemeData.length()).trim();
+ xpointer.addPart(new XmlnsPart(prefix, namespace));
+ namespaces.put(prefix, namespace);
+ } else if (schemeNamespace == null && XPOINTER.equals(schemeLocalName)) {
+ xpointer.addPart(new XPointerPart(schemeData));
+ } else {
+ xpointer.addPart(new UnsupportedPart(schemeName));
+ }
+ }
+}
+
+String schemeData():
+{
+ String temp;
+ StringBuilder schemeData = new StringBuilder();
+}
+{
+ (
+ ( temp = escapedData() { schemeData.append(temp); } )*
+ )
+ {
+ return unescape(schemeData.toString());
+ }
+}
+
+String escapedData():
+{
+ Token x;
+ String temp;
+ StringBuilder data = new StringBuilder();
+}
+{
+ // The reason for not making a token out of this all is that tokens cannot contain recursive definitions
+ (
+ x = <NormalChar> { data.append(x.image); }
+ | x = <CIRC_LBRACE> { data.append(x.image); }
+ | x = <CIRC_RBRACE> { data.append(x.image); }
+ | x = <DOUBLE_CIRC> { data.append(x.image); }
+ | x = <LBRACE> { data.append(x.image); }
+ temp = schemeData() { data.append(temp); }
+ x = <RBRACE> { data.append(x.image); }
+ )
+ {
+ return data.toString();
+ }
+}