/flow/src/java/org/apache/struts/flow/core/location/LocationAttributes.java
Java | 349 lines | 148 code | 42 blank | 159 comment | 23 complexity | 407ba9d6f59c770e2dabde545eed250f MD5 | raw file
- /*
- * 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.struts.flow.core.location;
- import org.w3c.dom.Attr;
- import org.w3c.dom.Element;
- import org.w3c.dom.Node;
- import org.w3c.dom.NodeList;
- import org.xml.sax.Attributes;
- import org.xml.sax.ContentHandler;
- import org.xml.sax.Locator;
- import org.xml.sax.SAXException;
- import org.xml.sax.helpers.AttributesImpl;
- /**
- * A class to handle location information stored in attributes.
- * These attributes are typically setup using {@link org.apache.struts.flow.core.location.LocationAttributes.Pipe}
- * which augments the SAX stream with additional attributes, e.g.:
- * <pre>
- * <root xmlns:loc="http://apache.org/cocoon/location"
- * loc:src="file://path/to/file.xml"
- * loc:line="1" loc:column="1">
- * <foo loc:src="file://path/to/file.xml" loc:line="2" loc:column="3"/>
- * </root>
- * </pre>
- *
- * @see org.apache.struts.flow.core.location.LocationAttributes.Pipe
- * @since 2.1.8
- * @version $Id: LocationAttributes.java 328390 2005-10-25 15:37:05Z sylvain $
- */
- 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";
-
- // 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 {@link Location} of an element (SAX flavor).
- *
- * @param attrs the element's attributes that hold the location information
- * @param description a description for the location (can be null)
- * @return a {@link Location} object
- */
- public static Location getLocation(Attributes attrs, String description) {
- String src = attrs.getValue(URI, SRC_ATTR);
- if (src == null) {
- return Location.UNKNOWN;
- }
-
- return new LocationImpl(description, src, getLine(attrs), getColumn(attrs));
- }
- /**
- * Returns the location of an element (SAX flavor). If the location is to be kept
- * into an object built from this element, consider using {@link #getLocation(Attributes)}
- * and the {@link Locatable} interface.
- *
- * @param attrs the element's attributes that hold the location information
- * @return a location string as defined by {@link Location#toString()}.
- */
- public static String getLocationString(Attributes attrs) {
- String src = attrs.getValue(URI, SRC_ATTR);
- if (src == null) {
- return LocationUtils.UNKNOWN_STRING;
- }
-
- 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 : LocationUtils.UNKNOWN_STRING;
- }
-
- /**
- * 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 {@link Location} of an element (DOM flavor).
- *
- * @param attrs the element that holds the location information
- * @param description a description for the location (if <code>null</code>, the element's name is used)
- * @return a {@link Location} object
- */
- public static Location getLocation(Element elem, String description) {
- Attr srcAttr = elem.getAttributeNodeNS(URI, SRC_ATTR);
- if (srcAttr == null) {
- return Location.UNKNOWN;
- }
- return new LocationImpl(description == null ? elem.getNodeName() : description,
- srcAttr.getValue(), getLine(elem), getColumn(elem));
- }
-
- /**
- * Same as <code>getLocation(elem, null)</code>.
- */
- public static Location getLocation(Element elem) {
- return getLocation(elem, null);
- }
-
- /**
- * Returns the location of an element that has been processed by this pipe (DOM flavor).
- * If the location is to be kept into an object built from this element, consider using
- * {@link #getLocation(Element)} and the {@link Locatable} interface.
- *
- * @param elem the element that holds the location information
- * @return a location string as defined by {@link Location#toString()}.
- */
- public static String getLocationString(Element elem) {
- Attr srcAttr = elem.getAttributeNodeNS(URI, SRC_ATTR);
- if (srcAttr == null) {
- return LocationUtils.UNKNOWN_STRING;
- }
-
- 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() : LocationUtils.UNKNOWN_STRING;
- }
- /**
- * 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;
- }
-
- /**
- * Remove the location attributes from a DOM element.
- *
- * @param elem the element to remove the location attributes from.
- * @param recurse if <code>true</code>, also remove location attributes on descendant elements.
- */
- public static void remove(Element elem, boolean recurse) {
- elem.removeAttributeNS(URI, SRC_ATTR);
- elem.removeAttributeNS(URI, LINE_ATTR);
- elem.removeAttributeNS(URI, COL_ATTR);
- if (recurse) {
- NodeList children = elem.getChildNodes();
- for (int i = 0; i < children.getLength(); i++) {
- Node child = children.item(i);
- if (child.getNodeType() == Node.ELEMENT_NODE) {
- remove((Element)child, recurse);
- }
- }
- }
- }
- /**
- * 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>
- * <root xmlns:loc="http://apache.org/cocoon/location"
- * loc:src="file://path/to/file.xml"
- * loc:line="1" loc:column="1">
- * <foo loc:src="file://path/to/file.xml" loc:line="2" loc:column="3"/>
- * </root>
- * </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.struts.flow.core.location.LocationAttributes
- * @since 2.1.8
- */
- public static class Pipe implements ContentHandler {
-
- private Locator locator;
-
- private ContentHandler nextHandler;
-
- /**
- * Create a filter. It has to be chained to another handler to be really useful.
- */
- public Pipe() {
- }
- /**
- * Create a filter that is chained to another handler.
- * @param next the next handler in the chain.
- */
- public Pipe(ContentHandler next) {
- nextHandler = next;
- }
- public void setDocumentLocator(Locator locator) {
- this.locator = locator;
- nextHandler.setDocumentLocator(locator);
- }
-
- public void startDocument() throws SAXException {
- nextHandler.startDocument();
- nextHandler.startPrefixMapping(LocationAttributes.PREFIX, LocationAttributes.URI);
- }
-
- public void endDocument() throws SAXException {
- endPrefixMapping(LocationAttributes.PREFIX);
- nextHandler.endDocument();
- }
- public void startElement(String uri, String loc, String raw, Attributes attrs) throws SAXException {
- // Add location attributes to the element
- nextHandler.startElement(uri, loc, raw, LocationAttributes.addLocationAttributes(locator, attrs));
- }
- public void endElement(String arg0, String arg1, String arg2) throws SAXException {
- nextHandler.endElement(arg0, arg1, arg2);
- }
- public void startPrefixMapping(String arg0, String arg1) throws SAXException {
- nextHandler.startPrefixMapping(arg0, arg1);
- }
- public void endPrefixMapping(String arg0) throws SAXException {
- nextHandler.endPrefixMapping(arg0);
- }
- public void characters(char[] arg0, int arg1, int arg2) throws SAXException {
- nextHandler.characters(arg0, arg1, arg2);
- }
- public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException {
- nextHandler.ignorableWhitespace(arg0, arg1, arg2);
- }
- public void processingInstruction(String arg0, String arg1) throws SAXException {
- nextHandler.processingInstruction(arg0, arg1);
- }
- public void skippedEntity(String arg0) throws SAXException {
- nextHandler.skippedEntity(arg0);
- }
- }
- }