You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by sy...@apache.org on 2005/07/29 12:39:36 UTC

svn commit: r226344 - in /cocoon: blocks/forms/trunk/java/org/apache/cocoon/forms/util/ trunk/ trunk/src/java/org/apache/cocoon/util/location/

Author: sylvain
Date: Fri Jul 29 03:39:26 2005
New Revision: 226344

URL: http://svn.apache.org/viewcvs?rev=226344&view=rev
Log:
Add location tracking utilities, remove CForms dependency on Xerces

Added:
    cocoon/trunk/src/java/org/apache/cocoon/util/location/
    cocoon/trunk/src/java/org/apache/cocoon/util/location/LocationAttributes.java   (with props)
    cocoon/trunk/src/java/org/apache/cocoon/util/location/LocatorToAttributesPipe.java   (with props)
    cocoon/trunk/src/java/org/apache/cocoon/util/location/package.html   (with props)
Modified:
    cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/util/DomHelper.java
    cocoon/trunk/status.xml

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/util/DomHelper.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/util/DomHelper.java?rev=226344&r1=226343&r2=226344&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/util/DomHelper.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/util/DomHelper.java Fri Jul 29 03:39:26 2005
@@ -25,19 +25,14 @@
 
 import org.apache.avalon.framework.service.ServiceException;
 import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.cocoon.util.location.LocationAttributes;
+import org.apache.cocoon.util.location.LocatorToAttributesPipe;
 import org.apache.cocoon.xml.SaxBuffer;
+import org.apache.cocoon.xml.dom.DOMBuilder;
 import org.apache.cocoon.xml.dom.DOMStreamer;
 import org.apache.commons.lang.BooleanUtils;
-import org.apache.excalibur.xml.EntityResolver;
+import org.apache.excalibur.xml.sax.SAXParser;
 import org.apache.excalibur.xml.sax.XMLizable;
-import org.apache.xerces.dom.NodeImpl;
-import org.apache.xerces.parsers.DOMParser;
-import org.apache.xerces.xni.Augmentations;
-import org.apache.xerces.xni.NamespaceContext;
-import org.apache.xerces.xni.QName;
-import org.apache.xerces.xni.XMLAttributes;
-import org.apache.xerces.xni.XMLLocator;
-import org.apache.xerces.xni.XNIException;
 import org.w3c.dom.Attr;
 import org.w3c.dom.CDATASection;
 import org.w3c.dom.Document;
@@ -46,7 +41,7 @@
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 import org.w3c.dom.Text;
-import org.w3c.dom.UserDataHandler;
+import org.xml.sax.ContentHandler;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
 import org.xml.sax.SAXNotSupportedException;
@@ -74,54 +69,19 @@
      * with the method {@link #parse(InputSource)} of this class.
      */
     public static String getLocation(Element element) {
-        String location = null;
-        if (element instanceof NodeImpl) {
-            location = (String)((NodeImpl)element).getUserData("location");
-        }
-
-        if (location != null) {
-            return location;
-        }
-        return "(location unknown)";
+        return LocationAttributes.getLocationString(element);
     }
     
     public static String getSystemIdLocation(Element element) {
-        String loc = getLocation(element);
-        if (loc.charAt(0) != '(') {
-            int end = loc.lastIndexOf(':');
-            if (end > 0) {
-                int start = loc.lastIndexOf(':', end - 1);
-                if (start >= 0) {
-                    return loc.substring(0, start);
-                }
-            }
-        }
-        return null;
+        return LocationAttributes.getURI(element);
     }
     
     public static int getLineLocation(Element element) {
-        String loc = getLocation(element);
-        if (loc.charAt(0) != '(') {
-            int end = loc.lastIndexOf(':');
-            if (end > 0) {
-                int start = loc.lastIndexOf(':', end - 1);
-                if (start >= 0) {
-                    return Integer.parseInt(loc.substring(start + 1, end));
-                }
-            }
-        }
-        return -1;
+        return LocationAttributes.getLine(element);
     }
 
     public static int getColumnLocation(Element element) {
-        String loc = getLocation(element);
-        if (loc.charAt(0) != '(') {
-            int end = loc.lastIndexOf(':');
-            if (end > 0) {
-                return Integer.parseInt(loc.substring(end));
-            }
-        }
-        return -1;
+        return LocationAttributes.getColumn(element);
     }
 
     /**
@@ -330,75 +290,20 @@
      */
     public static Document parse(InputSource inputSource, ServiceManager manager)
             throws SAXException, SAXNotSupportedException, IOException, ServiceException {
-        DOMParser domParser = new LocationTrackingDOMParser();
-        domParser.setFeature(
-                "http://apache.org/xml/features/dom/defer-node-expansion",
-                false);
-        domParser.setFeature(
-                "http://apache.org/xml/features/dom/create-entity-ref-nodes",
-                false);
         
-        EntityResolver resolver = null;
-        if (manager.hasService(EntityResolver.ROLE)) {
-            resolver = (EntityResolver)manager.lookup(EntityResolver.ROLE);
-            domParser.setEntityResolver(resolver);
-        }
+        SAXParser parser = (SAXParser)manager.lookup(SAXParser.ROLE);
+        DOMBuilder builder = new DOMBuilder();
+        
+        // Enhance the sax stream with location information
+        ContentHandler locationHandler = new LocatorToAttributesPipe(builder);
         
         try {
-            domParser.parse(inputSource);
-            return domParser.getDocument();
+            parser.parse(inputSource, locationHandler);
         } finally {
-            manager.release(resolver);
-        }
-    }
-
-    /**
-     * An extension of the Xerces DOM parser that puts the location of each
-     * node in that node's UserData.
-     */
-    public static class LocationTrackingDOMParser extends DOMParser {
-        XMLLocator locator;
-
-        public void startDocument(XMLLocator xmlLocator, String s,
-                NamespaceContext namespaceContext,
-                Augmentations augmentations) throws XNIException {
-            super.startDocument(xmlLocator, s, namespaceContext,
-                    augmentations);
-            this.locator = xmlLocator;
-            setLocation();
-        }
-
-        public void startElement(QName qName, XMLAttributes xmlAttributes,
-                Augmentations augmentations) throws XNIException {
-            super.startElement(qName, xmlAttributes, augmentations);
-            setLocation();
-        }
-
-        private final void setLocation() {
-            // Older versions of Xerces had a different signature for the
-            // startDocument method. If such a version is used, the
-            // startDocument method above will not be called and locator will
-            // hence be null.
-            // Tell the users this so that they don't get a stupid NPE.
-            if (this.locator == null) {
-                throw new RuntimeException(
-                        "Error: locator is null. Check that you have the" +
-                        " correct version of Xerces (such as the one that" +
-                        " comes with Cocoon) in your endorsed library path.");
-            }
-            NodeImpl node = null;
-            try {
-                node = (NodeImpl)this.getProperty(
-                        "http://apache.org/xml/properties/dom/current-element-node");
-            } catch (org.xml.sax.SAXException ex) {
-                System.err.println("except" + ex);
-            }
-            if (node != null) {
-                String location = locator.getLiteralSystemId() + ":" +
-                    locator.getLineNumber() + ":" + locator.getColumnNumber();
-                node.setUserData("location", location, (UserDataHandler)null);
-            }
+            manager.release(parser);
         }
+        
+        return builder.getDocument();
     }
 
     public static Map getLocalNSDeclarations(Element elm)

Added: cocoon/trunk/src/java/org/apache/cocoon/util/location/LocationAttributes.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/util/location/LocationAttributes.java?rev=226344&view=auto
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/util/location/LocationAttributes.java (added)
+++ cocoon/trunk/src/java/org/apache/cocoon/util/location/LocationAttributes.java Fri Jul 29 03:39:26 2005
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.location;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+import org.xml.sax.helpers.AttributesImpl;
+
+/**
+ * A class to handle location information stored in attributes.
+ * These attributes are typically setup using {@link LocatorToAttributesPipe}
+ * 
+ * @see LocatorToAttributesPipe
+ * @version $Id$
+ */
+public class LocationAttributes {
+    /** Prefix for the location namespace */
+    public static final String PREFIX = "loc";
+    /** Namespace URI for location attributes */
+    public static final String URI = "http://apache.org/cocoon/location";
+
+    /** Attribute name for the location URI */
+    public static final String SRC_ATTR  = "src";
+    /** Attribute name for the line number */
+    public static final String LINE_ATTR = "line";
+    /** Attribute name for the column number */
+    public static final String COL_ATTR  = "column";
+
+    /** Attribute qualified name for the location URI */
+    public static final String Q_SRC_ATTR  = "loc:src";
+    /** Attribute qualified name for the line number */
+    public static final String Q_LINE_ATTR = "loc:line";
+    /** Attribute qualified name for the column number */
+    public static final String Q_COL_ATTR  = "loc:column";
+    
+    /** Value returned when location is unknown */
+    public static final String UNKNOWN_LOCATION = "[unknown location]";
+    
+    // Private constructor, we only have static methods
+    private LocationAttributes() {
+        // Nothing
+    }
+    
+    /**
+     * Add location attributes to a set of SAX attributes.
+     * 
+     * @param locator the <code>Locator</code> (can be null)
+     * @param attrs the <code>Attributes</code> where locator information should be added
+     * @return
+     */
+    public static Attributes addLocationAttributes(Locator locator, Attributes attrs) {
+        if (locator == null || attrs.getIndex(URI, SRC_ATTR) != -1) {
+            // No location information known, or already has it
+            return attrs;
+        }
+        
+        // Get an AttributeImpl so that we can add new attributes.
+        AttributesImpl newAttrs = attrs instanceof AttributesImpl ?
+            (AttributesImpl)attrs : new AttributesImpl(attrs);
+
+        newAttrs.addAttribute(URI, SRC_ATTR, Q_SRC_ATTR, "CDATA", locator.getSystemId());
+        newAttrs.addAttribute(URI, LINE_ATTR, Q_LINE_ATTR, "CDATA", Integer.toString(locator.getLineNumber()));
+        newAttrs.addAttribute(URI, COL_ATTR, Q_COL_ATTR, "CDATA", Integer.toString(locator.getColumnNumber()));
+        
+        return newAttrs;
+    }
+
+    /**
+     * Returns the location of an element (SAX flavor).
+     * 
+     * @param attrs the element's attributes that hold the location information
+     * @return a location string of type "<code>foo.xml:10:80</code>" or
+     *        "<code>[unknown location]</code>" if <code>attrs</code> has no location information.
+     */
+    public static String getLocationString(Attributes attrs) {
+        String src = attrs.getValue(URI, SRC_ATTR);
+        if (src == null) {
+            return UNKNOWN_LOCATION;
+        }
+        
+        return src + ":" + attrs.getValue(URI, LINE_ATTR) + ":" + attrs.getValue(URI, COL_ATTR);
+    }
+    
+    /**
+     * Returns the URI of an element (SAX flavor)
+     * 
+     * @param attrs the element's attributes that hold the location information
+     * @return the element's URI or "<code>[unknown location]</code>" if <code>attrs</code>
+     *         has no location information.
+     */
+    public static String getURI(Attributes attrs) {
+        String src = attrs.getValue(URI, SRC_ATTR);
+        return src != null ? src : UNKNOWN_LOCATION;
+    }
+    
+    /**
+     * Returns the line number of an element (SAX flavor)
+     * 
+     * @param attrs the element's attributes that hold the location information
+     * @return the element's line number or <code>-1</code> if <code>attrs</code>
+     *         has no location information.
+     */
+    public static int getLine(Attributes attrs) {
+        String line = attrs.getValue(URI, LINE_ATTR);
+        return line != null ? Integer.parseInt(line) : -1;
+    }
+    
+    /**
+     * Returns the column number of an element (SAX flavor)
+     * 
+     * @param attrs the element's attributes that hold the location information
+     * @return the element's column number or <code>-1</code> if <code>attrs</code>
+     *         has no location information.
+     */
+    public static int getColumn(Attributes attrs) {
+        String col = attrs.getValue(URI, COL_ATTR);
+        return col != null ? Integer.parseInt(col) : -1;
+    }
+    
+    /**
+     * Returns the location of an element that has been processed by this pipe (DOM flavor).
+     * 
+     * @param elem the element that holds the location information
+     * @return a location string of type "<code>foo.xml:10:80</code>" or
+     *        "<code>[unknown location]</code>" if <code>attrs</code> has no location information.
+     */
+    public static String getLocationString(Element elem) {
+        Attr srcAttr = elem.getAttributeNodeNS(URI, SRC_ATTR);
+        if (srcAttr == null) {
+            return UNKNOWN_LOCATION;
+        }
+        
+        return srcAttr.getValue() + ":" + elem.getAttributeNS(URI, LINE_ATTR) + ":" + elem.getAttributeNS(URI, COL_ATTR);
+    }
+    
+    /**
+     * Returns the URI of an element (DOM flavor)
+     * 
+     * @param elem the element that holds the location information
+     * @return the element's URI or "<code>[unknown location]</code>" if <code>elem</code>
+     *         has no location information.
+     */
+    public static String getURI(Element elem) {
+        Attr attr = elem.getAttributeNodeNS(URI, SRC_ATTR);
+        return attr != null ? attr.getValue() : UNKNOWN_LOCATION;
+    }
+
+    /**
+     * Returns the line number of an element (DOM flavor)
+     * 
+     * @param elem the element that holds the location information
+     * @return the element's line number or <code>-1</code> if <code>elem</code>
+     *         has no location information.
+     */
+    public static int getLine(Element elem) {
+        Attr attr = elem.getAttributeNodeNS(URI, LINE_ATTR);
+        return attr != null ? Integer.parseInt(attr.getValue()) : -1;
+    }
+
+    /**
+     * Returns the column number of an element (DOM flavor)
+     * 
+     * @param elem the element that holds the location information
+     * @return the element's column number or <code>-1</code> if <code>elem</code>
+     *         has no location information.
+     */
+    public static int getColumn(Element elem) {
+        Attr attr = elem.getAttributeNodeNS(URI, COL_ATTR);
+        return attr != null ? Integer.parseInt(attr.getValue()) : -1;
+    }
+}

Propchange: cocoon/trunk/src/java/org/apache/cocoon/util/location/LocationAttributes.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/trunk/src/java/org/apache/cocoon/util/location/LocationAttributes.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: cocoon/trunk/src/java/org/apache/cocoon/util/location/LocatorToAttributesPipe.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/util/location/LocatorToAttributesPipe.java?rev=226344&view=auto
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/util/location/LocatorToAttributesPipe.java (added)
+++ cocoon/trunk/src/java/org/apache/cocoon/util/location/LocatorToAttributesPipe.java Fri Jul 29 03:39:26 2005
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.location;
+
+import org.apache.cocoon.xml.AbstractXMLPipe;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+
+/**
+ * A SAX filter that adds the information available from the <code>Locator</code> as attributes.
+ * The purpose of having location as attributes is to allow this information to survive transformations
+ * of the document (an XSL could copy these attributes over) or conversion of SAX events to a DOM.
+ * <p>
+ * The location is added as 3 attributes in a specific namespace to each element.
+ * <pre>
+ * &lt;root xmlns:loc="http://apache.org/cocoon/location"
+ *       loc:src="file://path/to/file.xml"
+ *       loc:line="1" loc:column="1"&gt;
+ *   &lt;foo loc:src="file://path/to/file.xml" loc:line="2" loc:column="3"/&gt;
+ * &lt;/root&gt;
+ * </pre>
+ * <strong>Note:</strong> Although this adds a lot of information to the serialized form of the document,
+ * the overhead in SAX events is not that big, as attribute names are interned, and all <code>src</code>
+ * attributes point to the same string.
+ * 
+ * @see org.apache.cocoon.util.location.LocationAttributes
+ * @version $Id$
+ */
+public class LocatorToAttributesPipe extends AbstractXMLPipe {
+    
+    private Locator locator;
+    
+    /**
+     * Create a filter. It has to be chained to another handler to be really useful.
+     */
+    public LocatorToAttributesPipe() {
+    }
+
+    /**
+     * Create a filter that is chained to another handler.
+     * @param next the next handler in the chain.
+     */
+    public LocatorToAttributesPipe(ContentHandler next) {
+        setContentHandler(next);
+    }
+
+    public void setDocumentLocator(Locator locator) {
+        this.locator = locator;
+        super.setDocumentLocator(locator);
+    }
+    
+    public void startDocument() throws SAXException {
+        super.startDocument();
+        super.startPrefixMapping(LocationAttributes.PREFIX, LocationAttributes.URI);
+    }
+    
+    public void endDocument() throws SAXException {
+        endPrefixMapping(LocationAttributes.PREFIX);
+        super.endDocument();
+    }
+
+    public void startElement(String uri, String loc, String raw, Attributes attrs) throws SAXException {
+        // Add location attributes to the element
+        super.startElement(uri, loc, raw, LocationAttributes.addLocationAttributes(locator, attrs));
+    }
+}

Propchange: cocoon/trunk/src/java/org/apache/cocoon/util/location/LocatorToAttributesPipe.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/trunk/src/java/org/apache/cocoon/util/location/LocatorToAttributesPipe.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: cocoon/trunk/src/java/org/apache/cocoon/util/location/package.html
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/util/location/package.html?rev=226344&view=auto
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/util/location/package.html (added)
+++ cocoon/trunk/src/java/org/apache/cocoon/util/location/package.html Fri Jul 29 03:39:26 2005
@@ -0,0 +1,3 @@
+<html>
+  <body>Classes and utilities used to track location information.</body>
+</html>
\ No newline at end of file

Propchange: cocoon/trunk/src/java/org/apache/cocoon/util/location/package.html
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/trunk/src/java/org/apache/cocoon/util/location/package.html
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: cocoon/trunk/status.xml
URL: http://svn.apache.org/viewcvs/cocoon/trunk/status.xml?rev=226344&r1=226343&r2=226344&view=diff
==============================================================================
--- cocoon/trunk/status.xml (original)
+++ cocoon/trunk/status.xml Fri Jul 29 03:39:26 2005
@@ -509,6 +509,10 @@
    </action>
   </release>
   <release version="2.1.8" date="TBD">
+    <action dev="SW" type="add">
+      New org.apache.cocoon.util.location package, providing utilities to track locations in XML documents and
+      the objects built from these documents.
+    </action>
     <action dev="SW" type="fix" fixes-bug="35618" due-to="Philippe Gassmann" due-to-email="phil@anyware-tech.com">
       Mail block: Allow any of the Cocoon-provided protocols to be used for attachments in SendMailTransformer.
       This means that "cocoon:" URLs are no more rewritten as external http requests.