You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

FONode.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. /*
  2. * Copyright 1999-2005 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /* $Id$ */
  17. package org.apache.fop.fo;
  18. // Java
  19. import java.util.ListIterator;
  20. import org.xml.sax.Attributes;
  21. import org.xml.sax.Locator;
  22. import org.xml.sax.helpers.LocatorImpl;
  23. import org.apache.commons.logging.Log;
  24. import org.apache.commons.logging.LogFactory;
  25. import org.apache.fop.apps.FOPException;
  26. import org.apache.fop.apps.FOUserAgent;
  27. import org.apache.fop.fo.extensions.ExtensionAttachment;
  28. import org.apache.fop.fo.extensions.ExtensionElementMapping;
  29. import org.apache.fop.fo.extensions.svg.SVGElementMapping;
  30. import org.apache.fop.fo.pagination.Root;
  31. import org.apache.fop.util.CharUtilities;
  32. /**
  33. * Base class for nodes in the XML tree
  34. */
  35. public abstract class FONode implements Cloneable {
  36. /** the XSL-FO namespace URI */
  37. protected static final String FO_URI = FOElementMapping.URI;
  38. /** Parent FO node */
  39. protected FONode parent;
  40. /**
  41. * Marks location of this object from the input FO
  42. * Call locator.getSystemId(), getLineNumber(),
  43. * getColumnNumber() for file, line, column
  44. * information
  45. */
  46. protected Locator locator;
  47. /** Logger for fo-tree related messages **/
  48. protected static Log log = LogFactory.getLog(FONode.class);
  49. //TODO Remove getLogger() method!
  50. /**
  51. * Main constructor.
  52. * @param parent parent of this node
  53. */
  54. protected FONode(FONode parent) {
  55. this.parent = parent;
  56. }
  57. /**
  58. * Perform a shallow cloning operation,
  59. * set its parent, and optionally clean the list of child nodes
  60. * @param cloneparent the intended parent of the clone
  61. * @param removeChildren if true, clean the list of child nodes
  62. * @return the cloned FO node
  63. * @throws FOPException if there's a problem while cloning the node
  64. */
  65. public FONode clone(FONode cloneparent, boolean removeChildren)
  66. throws FOPException {
  67. FONode foNode = (FONode) clone();
  68. foNode.parent = cloneparent;
  69. cloneparent.addChildNode(foNode);
  70. return foNode;
  71. }
  72. /**
  73. * Perform a shallow cloning operation
  74. *
  75. * @see java.lang.Object#clone()
  76. * @return the cloned object
  77. */
  78. protected Object clone() {
  79. try {
  80. return super.clone();
  81. } catch (CloneNotSupportedException e) {
  82. return null;
  83. }
  84. }
  85. /**
  86. * Set the location information for this element
  87. * @param locator the org.xml.sax.Locator object
  88. */
  89. public void setLocator(Locator locator) {
  90. if (locator != null) {
  91. //Create a copy of the locator so the info is preserved when we need to
  92. //give pointers during layout.
  93. this.locator = new LocatorImpl(locator);
  94. }
  95. }
  96. /** @return the location information for this element or null, if not available */
  97. public Locator getLocator() {
  98. return this.locator;
  99. }
  100. /**
  101. * Recursively goes up the FOTree hierarchy until the fo:root is found,
  102. * which returns the parent FOEventHandler.
  103. * @return the FOEventHandler object that is the parent of the FO Tree
  104. */
  105. public FOEventHandler getFOEventHandler() {
  106. return parent.getFOEventHandler();
  107. }
  108. /**
  109. * Returns the user agent for the node.
  110. * @return FOUserAgent
  111. */
  112. public FOUserAgent getUserAgent() {
  113. return getFOEventHandler().getUserAgent();
  114. }
  115. /**
  116. * Returns the logger for the node.
  117. * @return the logger
  118. */
  119. public Log getLogger() {
  120. return log;
  121. }
  122. /**
  123. * Initialize the node with its name, location information, and attributes
  124. * The attributes must be used immediately as the sax attributes
  125. * will be altered for the next element.
  126. * @param elementName element name (e.g., "fo:block")
  127. * @param locator Locator object (ignored by default)
  128. * @param attlist Collection of attributes passed to us from the parser.
  129. * @param pList the property list of the parent node
  130. * @throws FOPException for errors or inconsistencies in the attributes
  131. */
  132. public void processNode(String elementName, Locator locator,
  133. Attributes attlist, PropertyList pList) throws FOPException {
  134. if (log.isDebugEnabled()) {
  135. log.debug("Unhandled element: " + elementName
  136. + (locator != null ? " at " + getLocatorString(locator) : ""));
  137. }
  138. }
  139. /**
  140. * Create a property list for this node. Return null if the node does not
  141. * need a property list.
  142. * @param pList the closest parent propertylist.
  143. * @param foEventHandler The FOEventHandler where the PropertyListMaker
  144. * instance can be found.
  145. * @return A new property list.
  146. * @throws FOPException if there's a problem during processing
  147. */
  148. protected PropertyList createPropertyList(PropertyList pList, FOEventHandler foEventHandler)
  149. throws FOPException {
  150. return null;
  151. }
  152. /**
  153. * Checks to make sure, during SAX processing of input document, that the
  154. * incoming node is valid for the this (parent) node (e.g., checking to
  155. * see that fo:table is not an immediate child of fo:root)
  156. * called within FObj constructor
  157. * @param loc location in the FO source file
  158. * @param namespaceURI namespace of incoming node
  159. * @param localName (e.g. "table" for "fo:table")
  160. * @throws ValidationException if incoming node not valid for parent
  161. */
  162. protected void validateChildNode(Locator loc, String namespaceURI, String localName)
  163. throws ValidationException {
  164. //nop
  165. }
  166. /**
  167. * Adds characters (does nothing here)
  168. * @param data array of characters containing text to be added
  169. * @param start starting array element to add
  170. * @param end ending array element to add
  171. * @param pList currently applicable PropertyList
  172. * @param locator location in fo source file.
  173. * @throws FOPException if there's a problem during processing
  174. */
  175. protected void addCharacters(char[] data, int start, int end,
  176. PropertyList pList,
  177. Locator locator) throws FOPException {
  178. // ignore
  179. }
  180. /**
  181. * Called after processNode() is called. Subclasses can do additional processing.
  182. * @throws FOPException if there's a problem during processing
  183. */
  184. protected void startOfNode() throws FOPException {
  185. // do nothing by default
  186. }
  187. /**
  188. * Primarily used for making final content model validation checks
  189. * and/or informing the FOEventHandler that the end of this FO
  190. * has been reached.
  191. * @throws FOPException if there's a problem during processing
  192. */
  193. protected void endOfNode() throws FOPException {
  194. // do nothing by default
  195. }
  196. /**
  197. * Adds a node as a child of this node. The default implementation of this method
  198. * just ignores any child node being added.
  199. * @param child child node to be added to the childNodes of this node
  200. * @throws FOPException if there's a problem during processing
  201. */
  202. protected void addChildNode(FONode child) throws FOPException {
  203. // do nothing by default
  204. }
  205. /**
  206. * Removes a child node. Used by the child nodes to remove themselves, for
  207. * example table-body if it has no children.
  208. * @param child child node to be removed
  209. */
  210. public void removeChild(FONode child) {
  211. //nop
  212. }
  213. /**
  214. * @return the parent node of this node
  215. */
  216. public FONode getParent() {
  217. return this.parent;
  218. }
  219. /**
  220. * Return an iterator over all the child nodes of this FObj.
  221. * @return A ListIterator.
  222. */
  223. public ListIterator getChildNodes() {
  224. return null;
  225. }
  226. /**
  227. * Return an iterator over the object's child nodes starting
  228. * at the pased node.
  229. * @param childNode First node in the iterator
  230. * @return A ListIterator or null if child node isn't a child of
  231. * this FObj.
  232. */
  233. public ListIterator getChildNodes(FONode childNode) {
  234. return null;
  235. }
  236. /**
  237. * @return an iterator for the characters in this node
  238. */
  239. public CharIterator charIterator() {
  240. return new OneCharIterator(CharUtilities.CODE_EOT);
  241. }
  242. /**
  243. * Helper function to standardize the names of all namespace URI - local
  244. * name pairs in text messages.
  245. * For readability, using fo:, fox:, svg:, for those namespaces even
  246. * though that prefix may not have been chosen in the document.
  247. * @param namespaceURI URI of node found
  248. * (e.g., "http://www.w3.org/1999/XSL/Format")
  249. * @param localName local name of node, (e.g., "root" for "fo:root")
  250. * @return the prefix:localname, if fo/fox/svg, or a longer representation
  251. * with the unabbreviated URI otherwise.
  252. */
  253. public static String getNodeString(String namespaceURI, String localName) {
  254. if (namespaceURI.equals(FOElementMapping.URI)) {
  255. return "fo:" + localName;
  256. } else if (namespaceURI.equals(ExtensionElementMapping.URI)) {
  257. return "fox:" + localName;
  258. } else if (namespaceURI.equals(SVGElementMapping.URI)) {
  259. return "svg:" + localName;
  260. } else {
  261. return "(Namespace URI: \"" + namespaceURI + "\", "
  262. + "Local Name: \"" + localName + "\")";
  263. }
  264. }
  265. /**
  266. * Helper function to standardize property error exceptions
  267. * (e.g., not specifying either an internal- or an external-destination
  268. * property for an FO:link)
  269. * @param problem text to display that indicates the problem
  270. * @throws ValidationException the validation error provoked by the method call
  271. */
  272. protected void attributeError(String problem)
  273. throws ValidationException {
  274. throw new ValidationException(errorText(locator) + getName()
  275. + ", " + problem, locator);
  276. }
  277. /**
  278. * Helper function to standardize attribute warnings
  279. * (e.g., currently unsupported properties)
  280. * @param problem text to display that indicates the problem
  281. */
  282. protected void attributeWarning(String problem) {
  283. log.warn(warningText(locator) + getName() + ", " + problem);
  284. }
  285. /**
  286. * Helper function to standardize "too many" error exceptions
  287. * (e.g., two fo:declarations within fo:root)
  288. * @param loc org.xml.sax.Locator object of the error (*not* parent node)
  289. * @param nsURI namespace URI of incoming invalid node
  290. * @param lName local name (i.e., no prefix) of incoming node
  291. * @throws ValidationException the validation error provoked by the method call
  292. */
  293. protected void tooManyNodesError(Locator loc, String nsURI, String lName)
  294. throws ValidationException {
  295. throw new ValidationException(errorText(loc) + "For " + getName()
  296. + ", only one " + getNodeString(nsURI, lName) + " may be declared.",
  297. loc);
  298. }
  299. /**
  300. * Helper function to standardize "too many" error exceptions
  301. * (e.g., two fo:declarations within fo:root)
  302. * This overrloaded method helps make the caller code better self-documenting
  303. * @param loc org.xml.sax.Locator object of the error (*not* parent node)
  304. * @param offendingNode incoming node that would cause a duplication.
  305. * @throws ValidationException the validation error provoked by the method call
  306. */
  307. protected void tooManyNodesError(Locator loc, String offendingNode)
  308. throws ValidationException {
  309. throw new ValidationException(errorText(loc) + "For " + getName()
  310. + ", only one " + offendingNode + " may be declared.", loc);
  311. }
  312. /**
  313. * Helper function to standardize "out of order" exceptions
  314. * (e.g., fo:layout-master-set appearing after fo:page-sequence)
  315. * @param loc org.xml.sax.Locator object of the error (*not* parent node)
  316. * @param tooLateNode string name of node that should be earlier in document
  317. * @param tooEarlyNode string name of node that should be later in document
  318. * @throws ValidationException the validation error provoked by the method call
  319. */
  320. protected void nodesOutOfOrderError(Locator loc, String tooLateNode,
  321. String tooEarlyNode) throws ValidationException {
  322. throw new ValidationException(errorText(loc) + "For " + getName() + ", " + tooLateNode
  323. + " must be declared before " + tooEarlyNode + ".", loc);
  324. }
  325. /**
  326. * Helper function to return "invalid child" exceptions
  327. * (e.g., fo:block appearing immediately under fo:root)
  328. * @param loc org.xml.sax.Locator object of the error (*not* parent node)
  329. * @param nsURI namespace URI of incoming invalid node
  330. * @param lName local name (i.e., no prefix) of incoming node
  331. * @throws ValidationException the validation error provoked by the method call
  332. */
  333. protected void invalidChildError(Locator loc, String nsURI, String lName)
  334. throws ValidationException {
  335. invalidChildError(loc, nsURI, lName, null);
  336. }
  337. /**
  338. * Helper function to return "invalid child" exceptions with more
  339. * complex validation rules (i.e., needing more explanation of the problem)
  340. * @param loc org.xml.sax.Locator object of the error (*not* parent node)
  341. * @param nsURI namespace URI of incoming invalid node
  342. * @param lName local name (i.e., no prefix) of incoming node
  343. * @param ruleViolated text explanation of problem
  344. * @throws ValidationException the validation error provoked by the method call
  345. */
  346. protected void invalidChildError(Locator loc, String nsURI, String lName,
  347. String ruleViolated)
  348. throws ValidationException {
  349. throw new ValidationException(errorText(loc) + getNodeString(nsURI, lName)
  350. + " is not a valid child element of " + getName()
  351. + ((ruleViolated != null) ? ": " + ruleViolated : "."), loc);
  352. }
  353. /**
  354. * Helper function to throw an error caused by missing mandatory child elements.
  355. * E.g., fo:layout-master-set not having any page-master child element.
  356. * @param contentModel The XSL Content Model for the fo: object or a similar description
  357. * indicating the necessary child elements.
  358. * @throws ValidationException the validation error provoked by the method call
  359. */
  360. protected void missingChildElementError(String contentModel)
  361. throws ValidationException {
  362. throw new ValidationException(errorText(locator) + getName()
  363. + " is missing child elements. \nRequired Content Model: "
  364. + contentModel, locator);
  365. }
  366. /**
  367. * Helper function to throw an error caused by missing mandatory properties
  368. * @param propertyName the name of the missing property.
  369. * @throws ValidationException the validation error provoked by the method call
  370. */
  371. protected void missingPropertyError(String propertyName)
  372. throws ValidationException {
  373. throw new ValidationException(errorText(locator) + getName()
  374. + " is missing required \"" + propertyName + "\" property.", locator);
  375. }
  376. /**
  377. * Helper function to return "Error(line#/column#)" string for
  378. * above exception messages
  379. * @param loc org.xml.sax.Locator object
  380. * @return String opening error text
  381. */
  382. protected static String errorText(Locator loc) {
  383. return "Error(" + getLocatorString(loc) + "): ";
  384. }
  385. /**
  386. * Helper function to return "Warning(line#/column#)" string for
  387. * warning messages
  388. * @param loc org.xml.sax.Locator object
  389. * @return String opening warning text
  390. */
  391. protected static String warningText(Locator loc) {
  392. return "Warning(" + getLocatorString(loc) + "): ";
  393. }
  394. /**
  395. * Helper function to format a Locator instance.
  396. * @param loc org.xml.sax.Locator object
  397. * @return String the formatted text
  398. */
  399. public static String getLocatorString(Locator loc) {
  400. if (loc == null) {
  401. return "Unknown location";
  402. } else {
  403. return loc.getLineNumber() + "/" + loc.getColumnNumber();
  404. }
  405. }
  406. /**
  407. * Returns the root node of this tree
  408. * @return the root node
  409. */
  410. public Root getRoot() {
  411. return parent.getRoot();
  412. }
  413. /**
  414. * Returns the fully qualified name of the node
  415. * @return the fully qualified name of this node
  416. */
  417. public String getName() {
  418. return getName(getNormalNamespacePrefix());
  419. }
  420. /**
  421. * Returns the fully qualified name of the node
  422. * @param prefix the namespace prefix to build the name with (may be null)
  423. * @return the fully qualified name of this node
  424. */
  425. public String getName(String prefix) {
  426. if (prefix != null) {
  427. StringBuffer sb = new StringBuffer();
  428. sb.append(prefix).append(':').append(getLocalName());
  429. return sb.toString();
  430. } else {
  431. return getLocalName();
  432. }
  433. }
  434. /**
  435. * Returns the local name (i.e. without namespace prefix) of the node
  436. * @return the local name of this node
  437. */
  438. public abstract String getLocalName();
  439. /** @return the normally ussed namespace prefix for this kind of node (ex. "fo" for XSL-FO) */
  440. public abstract String getNormalNamespacePrefix();
  441. /** @return the namespace URI for this node */
  442. public String getNamespaceURI() {
  443. return null;
  444. }
  445. /**
  446. * Returns the Constants class integer value of this node
  447. * @return the integer enumeration of this FO (e.g., FO_ROOT)
  448. * if a formatting object, FO_UNKNOWN_NODE otherwise
  449. */
  450. public int getNameId() {
  451. return Constants.FO_UNKNOWN_NODE;
  452. }
  453. /**
  454. * This method is overridden by extension elements and allows the extension element
  455. * to return a pass-through attachment which the parent formatting objects should simply
  456. * carry with them but otherwise ignore. This mechanism is used to pass non-standard
  457. * information from the FO tree through to the layout engine and the renderers.
  458. * @return the extension attachment if one is created by the extension element, null otherwise.
  459. */
  460. public ExtensionAttachment getExtensionAttachment() {
  461. return null;
  462. }
  463. }