Browse Source

Implemented parsing of structure trees from IF XML files.


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@819585 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-1_0
Vincent Hennebert 14 years ago
parent
commit
3ec57c684b

+ 95
- 0
src/java/org/apache/fop/accessibility/ParsedStructureTree.java View File

@@ -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 <structure-tree> 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);
}

}

+ 113
- 0
src/java/org/apache/fop/accessibility/SimpleStructureTree.java View File

@@ -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();
}
}

}

+ 2
- 62
src/java/org/apache/fop/accessibility/StructureTree.java View File

@@ -19,62 +19,13 @@

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);
}
}
}

+ 1
- 1
src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java View 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);

+ 60
- 15
src/java/org/apache/fop/render/intermediate/IFParser.java View 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

Loading…
Cancel
Save