]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Implemented parsing of structure trees from IF XML files.
authorVincent Hennebert <vhennebert@apache.org>
Mon, 28 Sep 2009 15:27:30 +0000 (15:27 +0000)
committerVincent Hennebert <vhennebert@apache.org>
Mon, 28 Sep 2009 15:27:30 +0000 (15:27 +0000)
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@819585 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/fop/accessibility/ParsedStructureTree.java [new file with mode: 0644]
src/java/org/apache/fop/accessibility/SimpleStructureTree.java [new file with mode: 0644]
src/java/org/apache/fop/accessibility/StructureTree.java
src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java
src/java/org/apache/fop/render/intermediate/IFParser.java

diff --git a/src/java/org/apache/fop/accessibility/ParsedStructureTree.java b/src/java/org/apache/fop/accessibility/ParsedStructureTree.java
new file mode 100644 (file)
index 0000000..69b26c2
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.accessibility;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+
+import org.w3c.dom.NodeList;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
+import org.apache.fop.util.DelegatingContentHandler;
+
+/**
+ * A StructureTree implementation re-created from the structure stored in an IF
+ * XML document.
+ */
+public class ParsedStructureTree implements StructureTree {
+
+    private SAXTransformerFactory factory;
+
+    private List pageSequenceStructures = new ArrayList();
+
+    /**
+     * Creates a new instance.
+     *
+     * @param factory a factory internally used to build the structures of page
+     * sequences
+     */
+    public ParsedStructureTree(SAXTransformerFactory factory) {
+        this.factory = factory;
+    }
+
+    /**
+     * Returns a ContenHandler for parsing the structure of a new page sequence.
+     * It is assumed that page sequences are being parsed in the document order.
+     * This class will automatically number the structure trees.
+     *
+     * @return a handler for parsing the &lt;structure-tree&gt; element and its
+     * descendants
+     * @throws SAXException if there is an error when creating the handler
+     */
+    public ContentHandler getHandlerForNextPageSequence() throws SAXException {
+        TransformerHandler structureTreeBuilder;
+        try {
+            structureTreeBuilder = factory.newTransformerHandler();
+        } catch (TransformerConfigurationException e) {
+            throw new SAXException(e);
+        }
+        final DOMResult domResult = new DOMResult();
+        structureTreeBuilder.setResult(domResult);
+        return new DelegatingContentHandler(structureTreeBuilder) {
+
+            public void characters(char[] ch, int start, int length) throws SAXException {
+                /*
+                 * There's not text node in the structure tree. This is just
+                 * whitespace => ignore
+                 */
+            }
+
+            public void endDocument() throws SAXException {
+                super.endDocument();
+                pageSequenceStructures.add(domResult.getNode().getFirstChild().getChildNodes());
+            }
+        };
+    }
+
+    /** {@inheritDoc} */
+    public NodeList getPageSequence(int number) {
+        return (NodeList) pageSequenceStructures.get(number - 1);
+    }
+
+}
diff --git a/src/java/org/apache/fop/accessibility/SimpleStructureTree.java b/src/java/org/apache/fop/accessibility/SimpleStructureTree.java
new file mode 100644 (file)
index 0000000..e677572
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.accessibility;
+
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Iterator;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * A StructureTree implementation created from the reduced FO tree, in the form
+ * of a single DOM document obtained by XSL Transformation of the original FO
+ * tree.
+ */
+final class SimpleStructureTree implements StructureTree {
+
+    private final Node reducedFOTree;
+
+    private static class NamespaceContextImpl implements NamespaceContext {
+
+        private String uri;
+        private String prefix;
+
+        public NamespaceContextImpl() {
+        }
+
+        public NamespaceContextImpl(String prefix, String uri) {
+            this.uri = uri;
+            this.prefix = prefix;
+        }
+
+        public String getNamespaceURI(String prefix) {
+            return uri;
+        }
+
+        public void setNamespaceURI(String uri) {
+            this.uri = uri;
+        }
+
+        public String getPrefix(String uri) {
+            return prefix;
+        }
+
+        public void setPrefix(String prefix) {
+            this.prefix = prefix;
+        }
+
+        public Iterator getPrefixes(String uri) {
+            return null;
+        }
+    }
+
+    SimpleStructureTree(Node reducedFOTree) {
+        this.reducedFOTree = reducedFOTree;
+    }
+
+    /** {@inheritDoc} */
+    public NodeList getPageSequence(int number) {
+        XPath xpath = XPathFactory.newInstance().newXPath();
+        NamespaceContext namespaceContext = new NamespaceContextImpl("fo",
+                "http://www.w3.org/1999/XSL/Format");
+        xpath.setNamespaceContext(namespaceContext);
+        String xpathExpr = "/fo:root/fo:page-sequence[" + Integer.toString(number) + "]/*";
+
+        try {
+            return (NodeList) xpath.evaluate(xpathExpr, reducedFOTree, XPathConstants.NODESET);
+        } catch (XPathExpressionException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public String toString() {
+        try {
+            Transformer t = TransformerFactory.newInstance().newTransformer();
+            Writer str = new StringWriter();
+            t.transform(new DOMSource(reducedFOTree), new StreamResult(str));
+            return str.toString();
+        } catch (Exception e) {
+            return e.toString();
+        }
+    }
+
+}
index 0be785eb2ec6d09b068f352b77da73099c910f06..09a33f151133e62d44016719ec039b28f913cbd5 100644 (file)
 
 package org.apache.fop.accessibility;
 
-import java.util.Iterator;
-
-import javax.xml.namespace.NamespaceContext;
-import javax.xml.xpath.XPath;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpressionException;
-import javax.xml.xpath.XPathFactory;
-
-import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
 /**
  * A reduced version of the document's FO tree, containing only its logical
  * structure. Used by accessible output formats.
  */
-public final class StructureTree {
-
-    private final Node reducedFOTree;
-
-    private static class NamespaceContextImpl implements NamespaceContext {
-
-        private String uri;
-        private String prefix;
-
-        public NamespaceContextImpl() {
-        }
-
-        public NamespaceContextImpl(String prefix, String uri) {
-            this.uri = uri;
-            this.prefix = prefix;
-        }
-
-        public String getNamespaceURI(String prefix) {
-            return uri;
-        }
-
-        public void setNamespaceURI(String uri) {
-            this.uri = uri;
-        }
-
-        public String getPrefix(String uri) {
-            return prefix;
-        }
-
-        public void setPrefix(String prefix) {
-            this.prefix = prefix;
-        }
-
-        public Iterator getPrefixes(String uri) {
-            return null;
-        }
-    }
-
-    StructureTree(Node reducedFOTree) {
-        this.reducedFOTree = reducedFOTree;
-    }
+public interface StructureTree {
 
     /**
      * Returns the list of nodes that are the children of the given page sequence.
@@ -82,17 +33,6 @@ public final class StructureTree {
      * @param number number of the page sequence, 1-based
      * @return its children nodes
      */
-    public NodeList getPageSequence(int number) {
-        XPath xpath = XPathFactory.newInstance().newXPath();
-        NamespaceContext namespaceContext = new NamespaceContextImpl("fo",
-                "http://www.w3.org/1999/XSL/Format");
-        xpath.setNamespaceContext(namespaceContext);
-        String xpathExpr = "/fo:root/fo:page-sequence[" + Integer.toString(number) + "]/*";
+    NodeList getPageSequence(int number);
 
-        try {
-            return (NodeList) xpath.evaluate(xpathExpr, reducedFOTree, XPathConstants.NODESET);
-        } catch (XPathExpressionException e) {
-            throw new RuntimeException(e);
-        }
-    }
 }
index c89f72623ca98ec8e961323daec8f9019d9e164a..00d4a5b56cd6a60f44b234ab8b55a8d806c579cd 100644 (file)
@@ -78,7 +78,7 @@ class TransformerNodeEndProcessing extends TransformerNode {
             Source src = new StreamSource(new ByteArrayInputStream(enrichedFO));
             DOMResult res = new DOMResult();
             transformer.transform(src, res);
-            userAgent.setStructureTree(new StructureTree(res.getNode()));
+            userAgent.setStructureTree(new SimpleStructureTree(res.getNode()));
 
             SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
             saxParserFactory.setNamespaceAware(true);
index e374f82fac397f9190e54ea061659d701aa2b3fa..3dc44069298a8c42cee07246f88ed8891dc9b441 100644 (file)
@@ -33,20 +33,19 @@ import javax.xml.transform.TransformerException;
 import javax.xml.transform.sax.SAXResult;
 import javax.xml.transform.sax.SAXTransformerFactory;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.w3c.dom.DOMImplementation;
 import org.w3c.dom.Document;
-
 import org.xml.sax.Attributes;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.AttributesImpl;
 import org.xml.sax.helpers.DefaultHandler;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
 import org.apache.xmlgraphics.util.QName;
 
+import org.apache.fop.accessibility.ParsedStructureTree;
 import org.apache.fop.apps.FOUserAgent;
 import org.apache.fop.fo.ElementMapping;
 import org.apache.fop.fo.ElementMappingRegistry;
@@ -60,6 +59,7 @@ import org.apache.fop.util.ContentHandlerFactory;
 import org.apache.fop.util.ContentHandlerFactoryRegistry;
 import org.apache.fop.util.DOMBuilderContentHandlerFactory;
 import org.apache.fop.util.DefaultErrorListener;
+import org.apache.fop.util.DelegatingContentHandler;
 import org.apache.fop.util.XMLUtil;
 
 /**
@@ -150,6 +150,26 @@ public class IFParser implements IFConstants {
 
         private ContentHandler navParser;
 
+        private ParsedStructureTree structureTree;
+
+        private ContentHandler structureTreeBuilder;
+
+        private final class StructureTreeBuilder extends DelegatingContentHandler {
+
+            private Attributes pageSequenceAttributes;
+
+            private StructureTreeBuilder(Attributes pageSequenceAttributes,
+                    ParsedStructureTree structureTree) throws SAXException {
+                super(structureTree.getHandlerForNextPageSequence());
+                this.pageSequenceAttributes = new AttributesImpl(pageSequenceAttributes);
+            }
+
+            public void endDocument() throws SAXException {
+                super.endDocument();
+                startIFElement(EL_PAGE_SEQUENCE, pageSequenceAttributes);
+            }
+        }
+
         public Handler(IFDocumentHandler documentHandler, FOUserAgent userAgent,
                 ElementMappingRegistry elementMappingRegistry) {
             this.documentHandler = documentHandler;
@@ -173,6 +193,11 @@ public class IFParser implements IFConstants {
             elementHandlers.put(EL_LINE, new LineHandler());
             elementHandlers.put(EL_BORDER_RECT, new BorderRectHandler());
             elementHandlers.put(EL_IMAGE, new ImageHandler());
+
+            if (userAgent.isAccessibilityEnabled()) {
+                structureTree = new ParsedStructureTree(tFactory);
+                userAgent.setStructureTree(structureTree);
+            }
         }
 
         private void establishForeignAttributes(Map foreignAttributes) {
@@ -200,19 +225,20 @@ public class IFParser implements IFConstants {
             } else {
                 boolean handled = true;
                 if (NAMESPACE.equals(uri)) {
-                    lastAttributes = new AttributesImpl(attributes);
-                    ElementHandler elementHandler = (ElementHandler)elementHandlers.get(localName);
-                    content.setLength(0);
-                    ignoreCharacters = true;
-                    if (elementHandler != null) {
-                        ignoreCharacters = elementHandler.ignoreCharacters();
-                        try {
-                            elementHandler.startElement(attributes);
-                        } catch (IFException ife) {
-                            handleIFException(ife);
+                    if (localName.equals(EL_PAGE_SEQUENCE) && userAgent.isAccessibilityEnabled()) {
+                        structureTreeBuilder = new StructureTreeBuilder(attributes, structureTree);
+                    } else if (localName.equals(EL_STRUCTURE_TREE)) {
+                        if (userAgent.isAccessibilityEnabled()) {
+                            delegate = structureTreeBuilder;
+                        } else {
+                            /* Delegate to a handler that does nothing */
+                            delegate = new DefaultHandler();
                         }
+                        delegateDepth++;
+                        delegate.startDocument();
+                        delegate.startElement(uri, localName, qName, attributes);
                     } else {
-                        handled = false;
+                        handled = startIFElement(localName, attributes);
                     }
                 } else if (DocumentNavigationExtensionConstants.NAMESPACE.equals(uri)) {
                     if (this.navParser == null) {
@@ -256,6 +282,25 @@ public class IFParser implements IFConstants {
             }
         }
 
+        private boolean startIFElement(String localName, Attributes attributes)
+                throws SAXException {
+            lastAttributes = new AttributesImpl(attributes);
+            ElementHandler elementHandler = (ElementHandler)elementHandlers.get(localName);
+            content.setLength(0);
+            ignoreCharacters = true;
+            if (elementHandler != null) {
+                ignoreCharacters = elementHandler.ignoreCharacters();
+                try {
+                    elementHandler.startElement(attributes);
+                } catch (IFException ife) {
+                    handleIFException(ife);
+                }
+                return true;
+            } else {
+                return false;
+            }
+        }
+
         private void handleIFException(IFException ife) throws SAXException {
             if (ife.getCause() instanceof SAXException) {
                 //unwrap