| /* |
| * Copyright 1999-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. |
| */ |
| |
| /* $Id$ */ |
| |
| package org.apache.fop.fo; |
| |
| // Java |
| import java.util.ListIterator; |
| |
| import org.xml.sax.Attributes; |
| import org.xml.sax.Locator; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import org.apache.fop.apps.FOPException; |
| import org.apache.fop.apps.FOUserAgent; |
| import org.apache.fop.fo.extensions.ExtensionElementMapping; |
| import org.apache.fop.fo.extensions.svg.SVGElementMapping; |
| import org.apache.fop.fo.pagination.Root; |
| import org.apache.fop.util.CharUtilities; |
| |
| /** |
| * base class for nodes in the XML tree |
| */ |
| public abstract class FONode implements Cloneable { |
| |
| protected static String FO_URI = FOElementMapping.URI; |
| |
| /** Parent FO node */ |
| protected FONode parent; |
| |
| /** Marks location of this object from the input FO |
| * Call locator.getSystemId(), getLineNumber(), |
| * getColumnNumber() for file, line, column |
| * information |
| */ |
| public Locator locator; |
| |
| /** Logger for fo-tree related messages **/ |
| private static Log log = LogFactory.getLog(FONode.class); |
| |
| /** |
| * Main constructor. |
| * @param parent parent of this node |
| */ |
| protected FONode(FONode parent) { |
| this.parent = parent; |
| } |
| |
| /** |
| * Perform a shallow cloning operation, |
| * set its parent, and optionally clean the list of child nodes |
| * @param parent the intended parent of the clone |
| * @param removeChildren if true, clean the list of child nodes |
| * @return the cloned FO node |
| */ |
| public FONode clone(FONode parent, boolean removeChildren) |
| throws FOPException { |
| FONode foNode = (FONode) clone(); |
| foNode.parent = parent; |
| parent.addChildNode(foNode); |
| return foNode; |
| } |
| |
| /** |
| * Perform a shallow cloning operation |
| * |
| * @see java.lang.Object#clone() |
| * @return the cloned object |
| */ |
| protected Object clone() { |
| try { |
| return super.clone(); |
| } catch (CloneNotSupportedException e) { } |
| return null; |
| } |
| |
| /** |
| * Set the location information for this element |
| * @param locator the org.xml.sax.Locator object |
| */ |
| public void setLocator(Locator locator) { |
| if (locator != null) { |
| this.locator = locator; |
| } |
| } |
| |
| /** |
| * Recursively goes up the FOTree hierarchy until the fo:root is found, |
| * which returns the parent FOEventHandler. |
| * @return the FOEventHandler object that is the parent of the FO Tree |
| */ |
| public FOEventHandler getFOEventHandler() { |
| return parent.getFOEventHandler(); |
| } |
| |
| /** |
| * Returns the user agent for the node. |
| * @return FOUserAgent |
| */ |
| public FOUserAgent getUserAgent() { |
| return getFOEventHandler().getUserAgent(); |
| } |
| |
| /** |
| * Returns the logger for the node. |
| * @return the logger |
| */ |
| public Log getLogger() { |
| return log; |
| } |
| |
| /** |
| * Initialize the node with its name, location information, and attributes |
| * The attributes must be used immediately as the sax attributes |
| * will be altered for the next element. |
| * @param elementName element name (e.g., "fo:block") |
| * @param locator Locator object (ignored by default) |
| * @param attlist Collection of attributes passed to us from the parser. |
| * @throws FOPException for errors or inconsistencies in the attributes |
| */ |
| public void processNode(String elementName, Locator locator, |
| Attributes attlist, PropertyList parent) throws FOPException { |
| log.debug("name = " + elementName); |
| } |
| |
| /** |
| * Create a property list for this node. Return null if the node does not |
| * need a property list. |
| * @param parent the closest parent propertylist. |
| * @param foEventHandler The FOEventHandler where the PropertyListMaker |
| * instance can be found. |
| * @return A new property list. |
| */ |
| protected PropertyList createPropertyList(PropertyList parent, FOEventHandler foEventHandler) throws FOPException { |
| return null; |
| } |
| |
| /** |
| * Checks to make sure, during SAX processing of input document, that the |
| * incoming node is valid for the this (parent) node (e.g., checking to |
| * see that fo:table is not an immediate child of fo:root) |
| * called within FObj constructor |
| * @param namespaceURI namespace of incoming node |
| * @param localName (e.g. "table" for "fo:table") |
| * @throws ValidationException if incoming node not valid for parent |
| */ |
| protected void validateChildNode(Locator loc, String namespaceURI, String localName) |
| throws ValidationException {} |
| |
| /** |
| * Adds characters (does nothing here) |
| * @param data array of characters containing text to be added |
| * @param start starting array element to add |
| * @param end ending array element to add |
| * @param pList currently applicable PropertyList |
| * @param locator location in fo source file. |
| * @throws FOPException if there's a problem during processing |
| */ |
| protected void addCharacters(char[] data, int start, int end, |
| PropertyList pList, |
| Locator locator) throws FOPException { |
| // ignore |
| } |
| |
| /** |
| * |
| */ |
| protected void startOfNode() throws FOPException { |
| // do nothing by default |
| } |
| |
| /** |
| * Primarily used for making final content model validation checks |
| * and/or informing the FOEventHandler that the end of this FO |
| * has been reached. |
| */ |
| protected void endOfNode() throws FOPException { |
| // do nothing by default |
| } |
| |
| /** |
| * @param child child node to be added to the childNodes of this node |
| */ |
| protected void addChildNode(FONode child) throws FOPException { |
| } |
| |
| /** |
| * Removes a child node. Used by the child nodes to remove themselves, for |
| * example table-body if it has no children. |
| * @param child child node to be removed |
| */ |
| public void removeChild(FONode child) { |
| //nop |
| } |
| |
| /** |
| * @return the parent node of this node |
| */ |
| public FONode getParent() { |
| return this.parent; |
| } |
| |
| /** |
| * Return an iterator over all the child nodes of this FObj. |
| * @return A ListIterator. |
| */ |
| public ListIterator getChildNodes() { |
| return null; |
| } |
| |
| /** |
| * Return an iterator over the object's child nodes starting |
| * at the pased node. |
| * @param childNode First node in the iterator |
| * @return A ListIterator or null if child node isn't a child of |
| * this FObj. |
| */ |
| public ListIterator getChildNodes(FONode childNode) { |
| return null; |
| } |
| |
| /** |
| * @return an iterator for the characters in this node |
| */ |
| public CharIterator charIterator() { |
| return new OneCharIterator(CharUtilities.CODE_EOT); |
| } |
| |
| /** |
| * Helper function to standardize the names of all namespace URI - local |
| * name pairs in text messages. |
| * For readability, using fo:, fox:, svg:, for those namespaces even |
| * though that prefix may not have been chosen in the document. |
| * @param namespaceURI URI of node found |
| * (e.g., "http://www.w3.org/1999/XSL/Format") |
| * @param localName local name of node, (e.g., "root" for "fo:root") |
| * @return the prefix:localname, if fo/fox/svg, or a longer representation |
| * with the unabbreviated URI otherwise. |
| */ |
| public static String getNodeString(String namespaceURI, String localName) { |
| if (namespaceURI.equals(FOElementMapping.URI)) { |
| return "fo:" + localName; |
| } else if (namespaceURI.equals(ExtensionElementMapping.URI)) { |
| return "fox:" + localName; |
| } else if (namespaceURI.equals(SVGElementMapping.URI)) { |
| return "svg:" + localName; |
| } else |
| return "(Namespace URI: \"" + namespaceURI + "\", " + |
| "Local Name: \"" + localName + "\")"; |
| } |
| |
| /** |
| * Helper function to standardize property error exceptions |
| * (e.g., not specifying either an internal- or an external-destination |
| * property for an FO:link) |
| * @param problem text to display that indicates the problem |
| */ |
| protected void attributeError(String problem) |
| throws ValidationException { |
| throw new ValidationException(errorText(locator) + getName() + ", " + |
| problem, locator); |
| } |
| |
| /** |
| * Helper function to standardize attribute warnings |
| * (e.g., currently unsupported properties) |
| * @param problem text to display that indicates the problem |
| */ |
| protected void attributeWarning(String problem) { |
| getLogger().warn(errorText(locator) + getName() + ", " + problem); |
| } |
| |
| /** |
| * Helper function to standardize "too many" error exceptions |
| * (e.g., two fo:declarations within fo:root) |
| * @param loc org.xml.sax.Locator object of the error (*not* parent node) |
| * @param nsURI namespace URI of incoming invalid node |
| * @param lName local name (i.e., no prefix) of incoming node |
| */ |
| protected void tooManyNodesError(Locator loc, String nsURI, String lName) |
| throws ValidationException { |
| throw new ValidationException(errorText(loc) + "For " + getName() + |
| ", only one " + getNodeString(nsURI, lName) + " may be declared.", |
| loc); |
| } |
| |
| /** |
| * Helper function to standardize "too many" error exceptions |
| * (e.g., two fo:declarations within fo:root) |
| * This overrloaded method helps make the caller code better self-documenting |
| * @param loc org.xml.sax.Locator object of the error (*not* parent node) |
| * @param offendingNode incoming node that would cause a duplication. |
| */ |
| protected void tooManyNodesError(Locator loc, String offendingNode) |
| throws ValidationException { |
| throw new ValidationException(errorText(loc) + "For " + getName() + |
| ", only one " + offendingNode + " may be declared.", loc); |
| } |
| |
| /** |
| * Helper function to standardize "out of order" exceptions |
| * (e.g., fo:layout-master-set appearing after fo:page-sequence) |
| * @param loc org.xml.sax.Locator object of the error (*not* parent node) |
| * @param tooLateNode string name of node that should be earlier in document |
| * @param tooEarlyNode string name of node that should be later in document |
| */ |
| protected void nodesOutOfOrderError(Locator loc, String tooLateNode, |
| String tooEarlyNode) throws ValidationException { |
| throw new ValidationException(errorText(loc) + "For " + getName() + ", " + tooLateNode |
| + " must be declared before " + tooEarlyNode + ".", loc); |
| } |
| |
| /** |
| * Helper function to return "invalid child" exceptions |
| * (e.g., fo:block appearing immediately under fo:root) |
| * @param loc org.xml.sax.Locator object of the error (*not* parent node) |
| * @param nsURI namespace URI of incoming invalid node |
| * @param lName local name (i.e., no prefix) of incoming node |
| */ |
| protected void invalidChildError(Locator loc, String nsURI, String lName) |
| throws ValidationException { |
| invalidChildError(loc, nsURI, lName, null); |
| } |
| |
| /** |
| * Helper function to return "invalid child" exceptions with more |
| * complex validation rules (i.e., needing more explanation of the problem) |
| * @param loc org.xml.sax.Locator object of the error (*not* parent node) |
| * @param nsURI namespace URI of incoming invalid node |
| * @param lName local name (i.e., no prefix) of incoming node |
| * @param ruleViolated text explanation of problem |
| */ |
| protected void invalidChildError(Locator loc, String nsURI, String lName, |
| String ruleViolated) |
| throws ValidationException { |
| throw new ValidationException(errorText(loc) + getNodeString(nsURI, lName) + |
| " is not a valid child element of " + getName() |
| + ((ruleViolated != null) ? ": " + ruleViolated : "."), loc); |
| } |
| |
| /** |
| * Helper function to return missing child element errors |
| * (e.g., fo:layout-master-set not having any page-master child element) |
| * @param contentModel The XSL Content Model for the fo: object. |
| * or a similar description indicating child elements needed. |
| */ |
| protected void missingChildElementError(String contentModel) |
| throws ValidationException { |
| throw new ValidationException(errorText(locator) + getName() + |
| " is missing child elements. \nRequired Content Model: " |
| + contentModel, locator); |
| } |
| |
| /** |
| * Helper function to return missing child element errors |
| * (e.g., fo:layout-master-set not having any page-master child element) |
| * @param contentModel The XSL Content Model for the fo: object. |
| * or a similar description indicating child elements needed. |
| */ |
| protected void missingPropertyError(String propertyName) |
| throws ValidationException { |
| throw new ValidationException(errorText(locator) + getName() + |
| " is missing required \"" + propertyName + "\" property.", locator); |
| } |
| |
| /** |
| * Helper function to return "Error (line#/column#)" string for |
| * above exception messages |
| * @param loc org.xml.sax.Locator object |
| * @return String opening error text |
| */ |
| protected static String errorText(Locator loc) { |
| if (loc == null) { |
| return "Error(Unknown location): "; |
| } else { |
| return "Error(" + loc.getLineNumber() + "/" + loc.getColumnNumber() + "): "; |
| } |
| } |
| |
| /** |
| * Helper function to return "Warning (line#/column#)" string for |
| * warning messages |
| * @param loc org.xml.sax.Locator object |
| * @return String opening warning text |
| */ |
| protected static String warningText(Locator loc) { |
| if (loc == null) { |
| return "Warning(Unknown location): "; |
| } else { |
| return "Warning(" + loc.getLineNumber() + "/" + loc.getColumnNumber() + "): "; |
| } |
| } |
| |
| /** |
| * Returns the root node of this tree |
| * @return the root node |
| */ |
| public Root getRoot() { |
| return parent.getRoot(); |
| } |
| |
| /** |
| * Returns the name of the node |
| * @return the name of this node |
| */ |
| public String getName() { |
| return null; |
| } |
| |
| /** |
| * Returns the Constants class integer value of this node |
| * @return the integer enumeration of this FO (e.g., FO_ROOT) |
| * if a formatting object, FO_UNKNOWN_NODE otherwise |
| */ |
| public int getNameId() { |
| return Constants.FO_UNKNOWN_NODE; |
| } |
| |
| } |
| |