From 4e89f502c93d90df557cea370776c70cc649f988 Mon Sep 17 00:00:00 2001 From: Glen Mazza Date: Wed, 16 Jun 2004 23:40:58 +0000 Subject: [PATCH] 1. Valid node checking for LayoutMasterSet done. 2. Additional error message provided for missing required child elements of a node. 3. Removal of elementName from property list; redundant (retrievable via getFObj.getName()). Adding getName() to FObj so the element so fObj.getName() works. (Vielen Dank, Simon!) 4. Moving locator information from FObj to FONode so non-XSL NS elements will also have this information. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@197720 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/fo/FONode.java | 51 ++++++++++++++++++- src/java/org/apache/fop/fo/FOTreeBuilder.java | 7 ++- src/java/org/apache/fop/fo/FObj.java | 28 +++------- src/java/org/apache/fop/fo/PropertyList.java | 12 +---- src/java/org/apache/fop/fo/XMLObj.java | 1 + .../fop/fo/expr/PPColWidthFunction.java | 2 +- .../apache/fop/fo/extensions/Bookmarks.java | 8 +-- .../org/apache/fop/fo/flow/BasicLink.java | 2 +- src/java/org/apache/fop/fo/flow/Block.java | 3 +- src/java/org/apache/fop/fo/flow/Footnote.java | 1 + .../org/apache/fop/fo/flow/FootnoteBody.java | 1 + src/java/org/apache/fop/fo/flow/Inline.java | 4 +- .../org/apache/fop/fo/flow/TableBody.java | 1 + .../org/apache/fop/fo/flow/TableCell.java | 1 + .../fop/fo/pagination/ColorProfile.java | 7 ++- .../fop/fo/pagination/Declarations.java | 9 ++-- .../org/apache/fop/fo/pagination/Flow.java | 2 +- .../fop/fo/pagination/LayoutMasterSet.java | 23 +++++++++ .../fop/fo/pagination/PageSequence.java | 13 ++--- .../apache/fop/fo/pagination/RegionBA.java | 3 +- .../apache/fop/fo/pagination/RegionBASE.java | 6 ++- .../org/apache/fop/fo/pagination/Root.java | 2 +- 22 files changed, 129 insertions(+), 58 deletions(-) diff --git a/src/java/org/apache/fop/fo/FONode.java b/src/java/org/apache/fop/fo/FONode.java index 90775eacf..15593de46 100644 --- a/src/java/org/apache/fop/fo/FONode.java +++ b/src/java/org/apache/fop/fo/FONode.java @@ -46,6 +46,15 @@ public abstract class FONode { /** Name of the node */ protected String name; + /** Marks input file containing this object **/ + public String systemId; + + /** Marks line number of this object in the input file **/ + public int line; + + /** Marks column number of this object in the input file **/ + public int column; + /** * Main constructor. * @param parent parent of this node @@ -54,6 +63,18 @@ public abstract class FONode { this.parent = parent; } + /** + * Set the location information for this element + * @param locator the org.xml.sax.Locator object + */ + public void setLocation(Locator locator) { + if (locator != null) { + line = locator.getLineNumber(); + column = locator.getColumnNumber(); + systemId = locator.getSystemId(); + } + } + /** * Returns the user agent for the node. * @return FOUserAgent @@ -80,6 +101,7 @@ public abstract class FONode { * @throws FOPException for errors or inconsistencies in the attributes */ public void processNode(String elementName, Locator locator, Attributes attlist) throws FOPException { + System.out.println("name = " + elementName); this.name = elementName; } @@ -223,6 +245,7 @@ public abstract class FONode { /** * 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 offendingNode incoming node that would cause a duplication. */ protected void tooManyNodesError(Locator loc, String offendingNode) { @@ -234,6 +257,7 @@ public abstract class FONode { /** * 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 */ @@ -247,22 +271,47 @@ public abstract class FONode { /** * 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) { throw new IllegalArgumentException( errorText(loc) + getNodeString(nsURI, lName) + - " is not valid child element of " + getName() + "."); + " is not a valid child element of " + getName() + "."); } + /** + * 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) { + throw new IllegalArgumentException( + errorText(line, column) + getName() + " is missing child elements. \n" + + "Required Content Model: " + contentModel); + } + /** * 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) { return "Error(" + loc.getLineNumber() + "/" + loc.getColumnNumber() + "): "; } + + /** + * Helper function to return "Error (line#/column#)" string for + * above exception messages + * @param lineNumber - line number of node with error + * @param columnNumber - column number of node with error + * @return String opening error text + */ + protected static String errorText(int lineNumber, int columnNumber) { + return "Error(" + lineNumber + "/" + columnNumber + "): "; + } } diff --git a/src/java/org/apache/fop/fo/FOTreeBuilder.java b/src/java/org/apache/fop/fo/FOTreeBuilder.java index 95bb1402c..ffb45bfb7 100644 --- a/src/java/org/apache/fop/fo/FOTreeBuilder.java +++ b/src/java/org/apache/fop/fo/FOTreeBuilder.java @@ -268,7 +268,12 @@ public class FOTreeBuilder extends DefaultHandler { */ public void endElement(String uri, String localName, String rawName) throws SAXException { - currentFObj.end(); + try { + currentFObj.end(); + } catch (IllegalArgumentException e) { + throw new SAXException(e); + } + currentFObj = currentFObj.getParent(); } diff --git a/src/java/org/apache/fop/fo/FObj.java b/src/java/org/apache/fop/fo/FObj.java index 38a8738a4..ac90c68a8 100644 --- a/src/java/org/apache/fop/fo/FObj.java +++ b/src/java/org/apache/fop/fo/FObj.java @@ -56,15 +56,6 @@ public class FObj extends FONode implements Constants { /** Dynamic layout dimension. Used to resolve relative lengths. */ protected Map layoutDimension = null; - /** Marks input file containing this object **/ - public String systemId; - - /** Marks line number of this object in the input file **/ - public int line; - - /** Marks column number of this object in the input file **/ - public int column; - /** * Create a new formatting object. * All formatting object classes extend this class. @@ -102,18 +93,6 @@ public class FObj extends FONode implements Constants { name = "fo:" + str; } - /** - * Set the location information for this element - * @param locator the org.xml.sax.Locator object - */ - public void setLocation(Locator locator) { - if (locator != null) { - line = locator.getLineNumber(); - column = locator.getColumnNumber(); - systemId = locator.getSystemId(); - } - } - /** * Set properties for this FO based on node attributes * @param attlist Collection of attributes passed to us from the parser. @@ -126,7 +105,7 @@ public class FObj extends FONode implements Constants { parentPL = parentFO.getPropertiesForNamespace(FOElementMapping.URI); } - propertyList = new PropertyList(this, parentPL, FOElementMapping.URI, name); + propertyList = new PropertyList(this, parentPL, FOElementMapping.URI); propertyList.addAttributesToList(attlist); propMgr = new PropertyManager(propertyList); setWritingMode(); @@ -457,5 +436,10 @@ public class FObj extends FONode implements Constants { return getName() + " at line " + line + ":" + column; } */ + + public String getName() { + return null; + } + } diff --git a/src/java/org/apache/fop/fo/PropertyList.java b/src/java/org/apache/fop/fo/PropertyList.java index d5421c085..e03a4cacd 100644 --- a/src/java/org/apache/fop/fo/PropertyList.java +++ b/src/java/org/apache/fop/fo/PropertyList.java @@ -95,7 +95,6 @@ public class PropertyList extends HashMap { private PropertyList parentPropertyList = null; private String namespace = ""; - private String elementName = ""; private FObj fobj = null; /** @@ -103,14 +102,12 @@ public class PropertyList extends HashMap { * @param parentPropertyList the PropertyList belonging to the new objects * parent * @param space name of namespace - * @param elementName name of element */ public PropertyList(FObj fObjToAttach, PropertyList parentPropertyList, - String space, String elementName) { + String space) { this.fobj = fObjToAttach; this.parentPropertyList = parentPropertyList; this.namespace = space; - this.elementName = elementName; } /** @@ -145,13 +142,6 @@ public class PropertyList extends HashMap { return namespace; } - /** - * @return element name for this - */ - public String getElement() { - return elementName; - } - /** * Return the value explicitly specified on this FO. * @param propertyName The name of the property whose value is desired. diff --git a/src/java/org/apache/fop/fo/XMLObj.java b/src/java/org/apache/fop/fo/XMLObj.java index 91baef3fe..9d6b7f4cf 100644 --- a/src/java/org/apache/fop/fo/XMLObj.java +++ b/src/java/org/apache/fop/fo/XMLObj.java @@ -58,6 +58,7 @@ public abstract class XMLObj extends FONode { * @see org.apache.fop.fo.FONode#processNode */ public void processNode(String elementName, Locator locator, Attributes attlist) throws FOPException { + setLocation(locator); name = elementName; attr = attlist; } diff --git a/src/java/org/apache/fop/fo/expr/PPColWidthFunction.java b/src/java/org/apache/fop/fo/expr/PPColWidthFunction.java index 6eefd2637..ccdbf9829 100644 --- a/src/java/org/apache/fop/fo/expr/PPColWidthFunction.java +++ b/src/java/org/apache/fop/fo/expr/PPColWidthFunction.java @@ -52,7 +52,7 @@ public class PPColWidthFunction extends FunctionBase { throw new PropertyException("Non numeric operand to " + "proportional-column-width function"); } - if (!pInfo.getPropertyList().getElement().equals("fo:table-column")) { + if (!pInfo.getPropertyList().getFObj().getName().equals("fo:table-column")) { throw new PropertyException("proportional-column-width function " + "may only be used on table-column FO"); } diff --git a/src/java/org/apache/fop/fo/extensions/Bookmarks.java b/src/java/org/apache/fop/fo/extensions/Bookmarks.java index 8b5339012..e7d45f508 100644 --- a/src/java/org/apache/fop/fo/extensions/Bookmarks.java +++ b/src/java/org/apache/fop/fo/extensions/Bookmarks.java @@ -18,12 +18,14 @@ package org.apache.fop.fo.extensions; +// Java +import java.util.ArrayList; + +// FOP import org.apache.fop.fo.FONode; import org.apache.fop.fo.FOTreeVisitor; import org.apache.fop.fo.pagination.Root; -import java.util.ArrayList; - /** * Bookmarks data is the top level element of the pdf bookmark extension. * This handles the adding of outlines. When the element is ended it @@ -58,7 +60,7 @@ public class Bookmarks extends ExtensionObj { * the bookmark data from the child elements and add * the extension to the area tree. */ - public void end() { + protected void end() { ((Root) parent).setBookmarks(this); } diff --git a/src/java/org/apache/fop/fo/flow/BasicLink.java b/src/java/org/apache/fop/fo/flow/BasicLink.java index 728c12ae9..61edb839f 100644 --- a/src/java/org/apache/fop/fo/flow/BasicLink.java +++ b/src/java/org/apache/fop/fo/flow/BasicLink.java @@ -140,7 +140,7 @@ public class BasicLink extends Inline { /** * @see org.apache.fop.fo.FONode#end */ - public void end() { + protected void end() { super.end(); getFOInputHandler().endLink(); } diff --git a/src/java/org/apache/fop/fo/flow/Block.java b/src/java/org/apache/fop/fo/flow/Block.java index ade2ce9b1..f7f57ab54 100644 --- a/src/java/org/apache/fop/fo/flow/Block.java +++ b/src/java/org/apache/fop/fo/flow/Block.java @@ -20,6 +20,7 @@ package org.apache.fop.fo.flow; // XML import org.xml.sax.Attributes; +import org.xml.sax.SAXException; // FOP import org.apache.fop.apps.FOPException; @@ -236,7 +237,7 @@ public class Block extends FObjMixed { /** * @see org.apache.fop.fo.FONode#end */ - public void end() { + protected void end() { handleWhiteSpace(); getFOInputHandler().endBlock(this); } diff --git a/src/java/org/apache/fop/fo/flow/Footnote.java b/src/java/org/apache/fop/fo/flow/Footnote.java index d2b5e9361..83a50e50a 100644 --- a/src/java/org/apache/fop/fo/flow/Footnote.java +++ b/src/java/org/apache/fop/fo/flow/Footnote.java @@ -20,6 +20,7 @@ package org.apache.fop.fo.flow; // XML import org.xml.sax.Attributes; +import org.xml.sax.SAXException; // FOP import org.apache.fop.apps.FOPException; diff --git a/src/java/org/apache/fop/fo/flow/FootnoteBody.java b/src/java/org/apache/fop/fo/flow/FootnoteBody.java index 94fd38848..c0319d86a 100644 --- a/src/java/org/apache/fop/fo/flow/FootnoteBody.java +++ b/src/java/org/apache/fop/fo/flow/FootnoteBody.java @@ -20,6 +20,7 @@ package org.apache.fop.fo.flow; // XML import org.xml.sax.Attributes; +import org.xml.sax.SAXException; // FOP import org.apache.fop.apps.FOPException; diff --git a/src/java/org/apache/fop/fo/flow/Inline.java b/src/java/org/apache/fop/fo/flow/Inline.java index 076cb00ee..6de4dd77a 100644 --- a/src/java/org/apache/fop/fo/flow/Inline.java +++ b/src/java/org/apache/fop/fo/flow/Inline.java @@ -22,6 +22,7 @@ package org.apache.fop.fo.flow; import org.xml.sax.Attributes; // FOP +import org.apache.fop.apps.FOPException; import org.apache.fop.fo.CharIterator; import org.apache.fop.fo.FONode; import org.apache.fop.fo.FObjMixed; @@ -33,7 +34,6 @@ import org.apache.fop.fo.properties.CommonBackground; import org.apache.fop.fo.properties.CommonBorderAndPadding; import org.apache.fop.fo.properties.CommonMarginInline; import org.apache.fop.fo.properties.CommonRelativePosition; -import org.apache.fop.apps.FOPException; /** * Class modelling the fo:inline object. See Sec. 6.6.7 of the XSL-FO Standard. @@ -138,7 +138,7 @@ public class Inline extends FObjMixed { /** * @see org.apache.fop.fo.FONode#end */ - public void end() { + protected void end() { getFOInputHandler().endInline(this); } diff --git a/src/java/org/apache/fop/fo/flow/TableBody.java b/src/java/org/apache/fop/fo/flow/TableBody.java index ab8424d8b..90825dc18 100644 --- a/src/java/org/apache/fop/fo/flow/TableBody.java +++ b/src/java/org/apache/fop/fo/flow/TableBody.java @@ -20,6 +20,7 @@ package org.apache.fop.fo.flow; // XML import org.xml.sax.Attributes; +import org.xml.sax.SAXException; // FOP import org.apache.fop.apps.FOPException; diff --git a/src/java/org/apache/fop/fo/flow/TableCell.java b/src/java/org/apache/fop/fo/flow/TableCell.java index 7a2a09b02..b03d2c408 100644 --- a/src/java/org/apache/fop/fo/flow/TableCell.java +++ b/src/java/org/apache/fop/fo/flow/TableCell.java @@ -20,6 +20,7 @@ package org.apache.fop.fo.flow; // XML import org.xml.sax.Attributes; +import org.xml.sax.SAXException; // FOP import org.apache.fop.apps.FOPException; diff --git a/src/java/org/apache/fop/fo/pagination/ColorProfile.java b/src/java/org/apache/fop/fo/pagination/ColorProfile.java index 56a415c1b..f47654f6c 100644 --- a/src/java/org/apache/fop/fo/pagination/ColorProfile.java +++ b/src/java/org/apache/fop/fo/pagination/ColorProfile.java @@ -24,7 +24,10 @@ import java.awt.color.ICC_ColorSpace; import java.net.URL; import java.io.IOException; import java.io.InputStream; + +// XML import org.xml.sax.Locator; +import org.xml.sax.SAXException; // FOP import org.apache.fop.datatypes.ColorType; @@ -50,7 +53,7 @@ public class ColorProfile extends FObj { } /** - * @see org.apache.fop.fo.FONode#validateChildNode(String, String) + * @see org.apache.fop.fo.FONode#validateChildNode(Locator, String, String) XSL 1.0/FOP: EMPTY (no child nodes permitted) */ protected void validateChildNode(Locator loc, String nsURI, String localName) { @@ -62,7 +65,7 @@ public class ColorProfile extends FObj { * Extract instance variables from the collection of properties for this * object. */ - public void end() { + protected void end() { src = this.propertyList.get(PR_SRC).getString(); profileName = this.propertyList.get(PR_COLOR_PROFILE_NAME).getString(); intent = this.propertyList.get(PR_RENDERING_INTENT).getEnum(); diff --git a/src/java/org/apache/fop/fo/pagination/Declarations.java b/src/java/org/apache/fop/fo/pagination/Declarations.java index 3e0d3aa36..0a6c6c094 100644 --- a/src/java/org/apache/fop/fo/pagination/Declarations.java +++ b/src/java/org/apache/fop/fo/pagination/Declarations.java @@ -23,13 +23,16 @@ import java.util.List; import java.util.Map; import java.util.Iterator; +// XML +import org.xml.sax.Attributes; +import org.xml.sax.Locator; + // FOP import org.apache.fop.fo.FOElementMapping; import org.apache.fop.fo.FONode; import org.apache.fop.fo.FObj; import org.apache.fop.fo.FOTreeVisitor; import org.apache.fop.fo.XMLObj; -import org.xml.sax.Locator; /** @@ -53,7 +56,7 @@ public class Declarations extends FObj { } /** - * @see org.apache.fop.fo.FONode#validateChildNode(String, String) + * @see org.apache.fop.fo.FONode#validateChildNode(Locator, String, String) XSL 1.0: (color-profile)+ (and non-XSL NS nodes) FOP/XSL 1.1: (color-profile)* (and non-XSL NS nodes) */ @@ -69,7 +72,7 @@ public class Declarations extends FObj { * At the end of this element sort out the child into * a hashmap of color profiles and a list of external xml. */ - public void end() { + protected void end() { if (children != null) { for (Iterator iter = children.iterator(); iter.hasNext();) { FONode node = (FONode)iter.next(); diff --git a/src/java/org/apache/fop/fo/pagination/Flow.java b/src/java/org/apache/fop/fo/pagination/Flow.java index 64037dfc2..ac2911e9d 100644 --- a/src/java/org/apache/fop/fo/pagination/Flow.java +++ b/src/java/org/apache/fop/fo/pagination/Flow.java @@ -98,7 +98,7 @@ public class Flow extends FObj { /** * Tell the StructureRenderer that we are at the end of the flow. */ - public void end() { + protected void end() { getFOInputHandler().endFlow(this); } diff --git a/src/java/org/apache/fop/fo/pagination/LayoutMasterSet.java b/src/java/org/apache/fop/fo/pagination/LayoutMasterSet.java index 8ad7f982b..16e549489 100644 --- a/src/java/org/apache/fop/fo/pagination/LayoutMasterSet.java +++ b/src/java/org/apache/fop/fo/pagination/LayoutMasterSet.java @@ -28,8 +28,10 @@ import org.xml.sax.Attributes; // FOP import org.apache.fop.fo.FONode; import org.apache.fop.fo.FObj; +import org.apache.fop.fo.FOElementMapping; import org.apache.fop.fo.FOTreeVisitor; import org.apache.fop.apps.FOPException; +import org.xml.sax.Locator; /** * The layout-master-set formatting object. @@ -52,6 +54,27 @@ public class LayoutMasterSet extends FObj { super(parent); } + /** + * @see org.apache.fop.fo.FONode#validateChildNode(Locator, String, String) + XSL/FOP: (simple-page-master|page-sequence-master)+ + */ + protected void validateChildNode(Locator loc, String nsURI, String localName) { + if (nsURI == FOElementMapping.URI) { + if (!localName.equals("simple-page-master") + && !localName.equals("page-sequence-master")) { + invalidChildError(loc, nsURI, localName); + } + } else { + invalidChildError(loc, nsURI, localName); + } + } + + protected void end() { + if (children == null) { + missingChildElementError("(simple-page-master|page-sequence-master)+"); + } + } + /** * @see org.apache.fop.fo.FObj#addProperties */ diff --git a/src/java/org/apache/fop/fo/pagination/PageSequence.java b/src/java/org/apache/fop/fo/pagination/PageSequence.java index cc04488e1..fc4d041d7 100644 --- a/src/java/org/apache/fop/fo/pagination/PageSequence.java +++ b/src/java/org/apache/fop/fo/pagination/PageSequence.java @@ -18,17 +18,18 @@ package org.apache.fop.fo.pagination; +// Java +import java.util.HashMap; + +// XML +import org.xml.sax.Attributes; + // FOP import org.apache.fop.fo.FONode; import org.apache.fop.fo.FObj; import org.apache.fop.fo.FOTreeVisitor; import org.apache.fop.apps.FOPException; -// Java -import java.util.HashMap; - -import org.xml.sax.Attributes; - /** * This provides pagination of flows onto pages. Much of the * logic for paginating flows is contained in this class. @@ -301,7 +302,7 @@ public class PageSequence extends FObj { * This passes the end page sequence to the structure handler * so it can act upon that. */ - public void end() { + protected void end() { try { getFOInputHandler().endPageSequence(this); } catch (FOPException fopex) { diff --git a/src/java/org/apache/fop/fo/pagination/RegionBA.java b/src/java/org/apache/fop/fo/pagination/RegionBA.java index ca9622af3..64ef93b92 100644 --- a/src/java/org/apache/fop/fo/pagination/RegionBA.java +++ b/src/java/org/apache/fop/fo/pagination/RegionBA.java @@ -25,6 +25,7 @@ import java.awt.Rectangle; import org.apache.fop.fo.FONode; import org.apache.fop.fo.FOTreeVisitor; + /** * Abstract base class for fo:region-before and fo:region-after. */ @@ -49,7 +50,7 @@ public abstract class RegionBA extends RegionBASE { /** * @see org.apache.fop.fo.FONode#end() */ - public void end() { + protected void end() { super.end(); bPrecedence = (this.propertyList.get(PR_PRECEDENCE).getEnum() == Precedence.TRUE); diff --git a/src/java/org/apache/fop/fo/pagination/RegionBASE.java b/src/java/org/apache/fop/fo/pagination/RegionBASE.java index a411d1098..4a960c864 100644 --- a/src/java/org/apache/fop/fo/pagination/RegionBASE.java +++ b/src/java/org/apache/fop/fo/pagination/RegionBASE.java @@ -18,10 +18,14 @@ package org.apache.fop.fo.pagination; +// XML +import org.xml.sax.SAXException; + // FOP import org.apache.fop.fo.FONode; import org.apache.fop.fo.FOTreeVisitor; + /** * Base class for Before, After, Start and End regions (BASE). */ @@ -39,7 +43,7 @@ public abstract class RegionBASE extends Region { /** * @see org.apache.fop.fo.FONode#end() */ - public void end() { + protected void end() { // The problem with this is that it might not be known yet.... // Supposing extent is calculated in terms of percentage this.extent = this.propertyList.get(PR_EXTENT).getLength().getValue(); diff --git a/src/java/org/apache/fop/fo/pagination/Root.java b/src/java/org/apache/fop/fo/pagination/Root.java index 46a9bf36c..1b7cd2f7f 100644 --- a/src/java/org/apache/fop/fo/pagination/Root.java +++ b/src/java/org/apache/fop/fo/pagination/Root.java @@ -66,7 +66,7 @@ public class Root extends FObj { } /** - * @see org.apache.fop.fo.FONode#validateChildNode(String, String) + * @see org.apache.fop.fo.FONode#validateChildNode(Locator, String, String) XSL 1.0 Spec: (layout-master-set,declarations?,page-sequence+) FOP: (layout-master-set, declarations?, fox:bookmarks?, page-sequence+) */ -- 2.39.5