aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache/fop/util
diff options
context:
space:
mode:
authorJeremias Maerki <jeremias@apache.org>2006-02-17 10:57:15 +0000
committerJeremias Maerki <jeremias@apache.org>2006-02-17 10:57:15 +0000
commitc939529a9baf1a9ac1d16f935e8f11c89ca77be2 (patch)
tree1c6f827ad2421ba2ded81d2c8f4e15f196c9075e /src/java/org/apache/fop/util
parent90a82aaadad9c950b0c12c33ffb8b4d7201df286 (diff)
downloadxmlgraphics-fop-c939529a9baf1a9ac1d16f935e8f11c89ca77be2.tar.gz
xmlgraphics-fop-c939529a9baf1a9ac1d16f935e8f11c89ca77be2.zip
Initial support for XMP metadata (PDF 1.4) under fo:declarations. Both xmpmeta and RDF elements can be used as root elements for XMP metadata.
Extracted DOM2SAX functionality from XMLXMLHandler into utility class since it is now reused elsewhere. New DOMBuilderContentHandlerFactory is used to create ContentHandlers that build generic DOMs. New DelegatingContentHandler is a convenience base class modelled after XMLFilterImpl but as passive SAX receiver. It is used by DOMBuilderContentHandlerFactory. Refactored FOTreeBuilder. FO tree building is now in a special ContentHandler which can be replaced temporarily when handling foreign XML like SVG or XMP. Extension Elements wanting the set their own ContentHandlers (instead of using the standard FO tree building mechanism) return a non-null value in getContentHandlerFactory(). The old mechanism is still supported (MathML, Plan and Barcode4J still use that). However, SVG support is changed to use a ContentHandlerFactory. Extension elements for xmpmeta and RDF elements making use of the new DOM build-up using ContentHandlerFactory. XMP metadata is passed to the renderer as ExtensionAttachment to the document. Only PDFRenderer uses the XMP extension attachment at this time. The PDFRenderer automatically builds XMP metadata based on the basic metadata information in the PDFInfo object if no explicit XMP metadata has been added to the XSL-FO document. XMP metadata merging is not implemented because this would involve a more sophisticated XMP infrastructure. That also means that XMP metadata is not validated. It's passed into the PDF as is. The PDF library now provides the PDFMetadata class to embed XMP metadata in PDFs version >=1.4. stream contents use a special filter list which is initially empty, so non-PDF-aware XMP readers can extract (and optionally modify) the XMP metadata. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@378482 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/fop/util')
-rw-r--r--src/java/org/apache/fop/util/ContentHandlerFactory.java25
-rw-r--r--src/java/org/apache/fop/util/DOM2SAX.java133
-rw-r--r--src/java/org/apache/fop/util/DOMBuilderContentHandlerFactory.java138
-rw-r--r--src/java/org/apache/fop/util/DelegatingContentHandler.java314
4 files changed, 609 insertions, 1 deletions
diff --git a/src/java/org/apache/fop/util/ContentHandlerFactory.java b/src/java/org/apache/fop/util/ContentHandlerFactory.java
index da615cc54..a17d7a60f 100644
--- a/src/java/org/apache/fop/util/ContentHandlerFactory.java
+++ b/src/java/org/apache/fop/util/ContentHandlerFactory.java
@@ -18,7 +18,10 @@
package org.apache.fop.util;
+import java.util.EventListener;
+
import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
/**
* Factory interface implemented by classes that can instantiate ContentHandler subclasses which
@@ -33,8 +36,9 @@ public interface ContentHandlerFactory {
/**
* @return a new ContentHandler to handle a SAX stream
+ * @throws SAXException if there's an error while preparing the ContentHandler
*/
- ContentHandler createContentHandler();
+ ContentHandler createContentHandler() throws SAXException;
/**
* Interface that ContentHandler implementations that parse Java objects from XML can implement
@@ -46,6 +50,25 @@ public interface ContentHandlerFactory {
* @return the object parsed from the SAX stream (call valid after parsing)
*/
Object getObject();
+
+ /**
+ * Set a listener which gets notified when the object is fully built.
+ * @param listener the listener which gets notified
+ */
+ void setObjectBuiltListener(ObjectBuiltListener listener);
+ }
+
+ /**
+ * EventListener interface for objects which want to get notified when ContentHandler
+ * implementing the ObjectSource interface has finished parsing.
+ */
+ public interface ObjectBuiltListener extends EventListener {
+
+ /**
+ * Notifies the listener when the object is fully built.
+ * @param obj the newly built object
+ */
+ void notifyObjectBuilt(Object obj);
}
diff --git a/src/java/org/apache/fop/util/DOM2SAX.java b/src/java/org/apache/fop/util/DOM2SAX.java
new file mode 100644
index 000000000..a26e71429
--- /dev/null
+++ b/src/java/org/apache/fop/util/DOM2SAX.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2006 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.util;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.ext.LexicalHandler;
+import org.xml.sax.helpers.AttributesImpl;
+
+/**
+ * Helper class that produces a SAX stream from a DOM Document.
+ */
+public class DOM2SAX {
+
+ /** Logging instance */
+ private static Log log = LogFactory.getLog(DOM2SAX.class);
+
+ /**
+ * Writes the given document using the given TransformerHandler.
+ * @param doc DOM document
+ * @param handler TransformerHandler to write to
+ * @throws SAXException In case of a problem while writing XML
+ */
+ public static void writeDocument(Document doc,
+ ContentHandler handler) throws SAXException {
+ AttributesImpl atts = new AttributesImpl();
+ for (Node n = doc.getFirstChild(); n != null;
+ n = n.getNextSibling()) {
+ writeNode(n, handler, atts);
+ }
+ }
+
+ /**
+ * Writes a node using the given writer.
+ * @param node node to serialize
+ * @param handler ContentHandler to write to
+ * @param atts AttributesImpl instance that is reused during SAX event generation
+ * @throws SAXException In case of a problem while writing XML
+ */
+ private static void writeNode(Node node, ContentHandler handler, AttributesImpl atts)
+ throws SAXException {
+ char[] ca;
+ switch (node.getNodeType()) {
+ case Node.ELEMENT_NODE:
+ atts.clear();
+
+ if (node.hasAttributes()) {
+ NamedNodeMap attr = node.getAttributes();
+ int len = attr.getLength();
+ for (int i = 0; i < len; i++) {
+ Attr a = (Attr) attr.item(i);
+ atts.addAttribute("", a.getNodeName(), a.getNodeName(),
+ "CDATA", a.getNodeValue());
+ }
+ }
+ handler.startElement(node.getNamespaceURI(),
+ node.getLocalName(), node.getLocalName(), atts);
+
+ Node c = node.getFirstChild();
+ if (c != null) {
+ for (; c != null; c = c.getNextSibling()) {
+ writeNode(c, handler, atts);
+ }
+ }
+ handler.endElement(node.getNamespaceURI(), node.getNodeName(), node.getNodeName());
+ break;
+ case Node.TEXT_NODE:
+ ca = node.getNodeValue().toCharArray();
+ handler.characters(ca, 0, ca.length);
+ break;
+ case Node.CDATA_SECTION_NODE:
+ ca = node.getNodeValue().toCharArray();
+ if (handler instanceof LexicalHandler) {
+ LexicalHandler lh = (LexicalHandler)handler;
+ lh.startCDATA();
+ handler.characters(ca, 0, ca.length);
+ lh.endCDATA();
+ } else {
+ handler.characters(ca, 0, ca.length);
+ }
+ break;
+ case Node.ENTITY_REFERENCE_NODE:
+ log.warn("Ignoring ENTITY_REFERENCE_NODE. NYI");
+ /*
+ writer.write("&");
+ writer.write();
+ writer.write(";");
+ */
+ break;
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ handler.processingInstruction(node.getNodeName(), node.getNodeValue());
+ break;
+ case Node.COMMENT_NODE:
+ ca = node.getNodeValue().toCharArray();
+ if (handler instanceof LexicalHandler) {
+ LexicalHandler lh = (LexicalHandler)handler;
+ lh.comment(ca, 0, ca.length);
+ }
+ break;
+ case Node.DOCUMENT_TYPE_NODE:
+ break;
+ default:
+ throw new IllegalArgumentException("Unexpected node type ("
+ + node.getNodeType() + ")");
+ }
+ }
+
+
+}
diff --git a/src/java/org/apache/fop/util/DOMBuilderContentHandlerFactory.java b/src/java/org/apache/fop/util/DOMBuilderContentHandlerFactory.java
new file mode 100644
index 000000000..5b5dd3b48
--- /dev/null
+++ b/src/java/org/apache/fop/util/DOMBuilderContentHandlerFactory.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2006 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.util;
+
+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.DOMImplementation;
+import org.w3c.dom.Document;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
+/**
+ * ContentHandlerFactory which constructs ContentHandlers that build DOM Documents.
+ */
+public class DOMBuilderContentHandlerFactory implements ContentHandlerFactory {
+
+ private static SAXTransformerFactory tFactory
+ = (SAXTransformerFactory)SAXTransformerFactory.newInstance();
+
+ private String namespaceURI;
+ private DOMImplementation domImplementation;
+
+ /**
+ * Main Constructor
+ * @param namespaceURI the main namespace URI for the DOM to be parsed
+ * @param domImplementation the DOMImplementation to use for build the DOM
+ */
+ public DOMBuilderContentHandlerFactory(String namespaceURI,
+ DOMImplementation domImplementation) {
+ this.namespaceURI = namespaceURI;
+ this.domImplementation = domImplementation;
+ }
+
+ /** @see org.apache.fop.util.ContentHandlerFactory#getSupportedNamespaces() */
+ public String[] getSupportedNamespaces() {
+ return new String[] {namespaceURI};
+ }
+
+ /** @see org.apache.fop.util.ContentHandlerFactory#createContentHandler() */
+ public ContentHandler createContentHandler() throws SAXException {
+ return new Handler();
+ }
+
+ private class Handler extends DelegatingContentHandler
+ implements ContentHandlerFactory.ObjectSource {
+
+ private Document doc;
+ private ObjectBuiltListener obListener;
+
+ public Handler() throws SAXException {
+ super();
+ }
+
+ public Document getDocument() {
+ return this.doc;
+ }
+
+ /**
+ * @see org.apache.fop.util.ContentHandlerFactory.ObjectSource#getObject()
+ */
+ public Object getObject() {
+ return getDocument();
+ }
+
+ /**
+ * @see org.apache.fop.util.ContentHandlerFactory.ObjectSource
+ */
+ public void setObjectBuiltListener(ObjectBuiltListener listener) {
+ this.obListener = listener;
+ }
+
+ /**
+ * @see org.apache.fop.util.DelegatingContentHandler#startDocument()
+ */
+ public void startDocument() throws SAXException {
+ //Suppress startDocument() call if doc has not been set, yet. It will be done later.
+ if (doc != null) {
+ super.startDocument();
+ }
+ }
+
+ /**
+ * @see org.apache.fop.util.DelegatingContentHandler
+ */
+ public void startElement(String uri, String localName, String qName, Attributes atts)
+ throws SAXException {
+ if (doc == null) {
+ TransformerHandler handler;
+ try {
+ handler = tFactory.newTransformerHandler();
+ } catch (TransformerConfigurationException e) {
+ throw new SAXException("Error creating a new TransformerHandler", e);
+ }
+ doc = domImplementation.createDocument(namespaceURI, qName, null);
+ //It's easier to work with an empty document, so remove the root element
+ doc.removeChild(doc.getDocumentElement());
+ handler.setResult(new DOMResult(doc));
+ setDelegateContentHandler(handler);
+ setDelegateLexicalHandler(handler);
+ setDelegateDTDHandler(handler);
+ handler.startDocument();
+ }
+ super.startElement(uri, localName, qName, atts);
+ }
+
+ /**
+ * @see org.apache.fop.util.DelegatingContentHandler#endDocument()
+ */
+ public void endDocument() throws SAXException {
+ super.endDocument();
+ if (obListener != null) {
+ obListener.notifyObjectBuilt(getObject());
+ }
+ }
+
+ }
+
+}
diff --git a/src/java/org/apache/fop/util/DelegatingContentHandler.java b/src/java/org/apache/fop/util/DelegatingContentHandler.java
new file mode 100644
index 000000000..86cfb1e41
--- /dev/null
+++ b/src/java/org/apache/fop/util/DelegatingContentHandler.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright 2006 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.util;
+
+import java.io.IOException;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.DTDHandler;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.ext.LexicalHandler;
+
+/**
+ * SAX 2 Event Handler which simply delegates all calls to another ContentHandler. Subclasses can
+ * do additional processing. This class is the passive counterpart to XMLFilterImpl.
+ * <p>
+ * The ContentHandler is the only instance that is required. All others (DTDHandler,
+ * EntityResolver, LexicalHandler and ErrorHandler) may be ignored.
+ *
+ */
+public class DelegatingContentHandler
+ implements EntityResolver, DTDHandler, ContentHandler, LexicalHandler, ErrorHandler {
+
+ private ContentHandler delegate;
+ private EntityResolver entityResolver;
+ private DTDHandler dtdHandler;
+ private LexicalHandler lexicalHandler;
+ private ErrorHandler errorHandler;
+
+ /**
+ * Main constructor.
+ */
+ public DelegatingContentHandler() {
+ //nop
+ }
+
+ /**
+ * @return the delegate that all ContentHandler events are forwarded to
+ */
+ public ContentHandler getDelegateContentHandler() {
+ return this.delegate;
+ }
+
+ /**
+ * Sets the delegate ContentHandler that all events are forwarded to.
+ * @param handler the delegate instance
+ */
+ public void setDelegateContentHandler(ContentHandler handler) {
+ this.delegate = handler;
+ }
+
+ /**
+ * Sets the delegate EntityResolver.
+ * @param resolver the delegate instance
+ */
+ public void setDelegateEntityResolver(EntityResolver resolver) {
+ this.entityResolver = resolver;
+ }
+
+ /**
+ * Sets the delegate DTDHandler.
+ * @param handler the delegate instance
+ */
+ public void setDelegateDTDHandler(DTDHandler handler) {
+ this.dtdHandler = handler;
+ }
+
+ /**
+ * Sets the delegate LexicalHandler.
+ * @param handler the delegate instance
+ */
+ public void setDelegateLexicalHandler(LexicalHandler handler) {
+ this.lexicalHandler = handler;
+ }
+
+ /**
+ * Sets the delegate ErrorHandler.
+ * @param handler the delegate instance
+ */
+ public void setDelegateErrorHandler(ErrorHandler handler) {
+ this.errorHandler = handler;
+ }
+
+ // ==== EntityResolver
+
+ /**
+ * @see org.xml.sax.EntityResolver#resolveEntity(java.lang.String, java.lang.String)
+ */
+ public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
+ if (entityResolver != null) {
+ return entityResolver.resolveEntity(publicId, systemId);
+ } else {
+ return null;
+ }
+ }
+
+ // ==== DTDHandler
+
+ /**
+ * @see org.xml.sax.DTDHandler#notationDecl(java.lang.String, java.lang.String, java.lang.String)
+ */
+ public void notationDecl(String name, String publicId, String systemId) throws SAXException {
+ if (dtdHandler != null) {
+ dtdHandler.notationDecl(name, publicId, systemId);
+ }
+ }
+
+ /**
+ * @see org.xml.sax.DTDHandler#unparsedEntityDecl(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
+ */
+ public void unparsedEntityDecl(String name, String publicId, String systemId,
+ String notationName) throws SAXException {
+ if (dtdHandler != null) {
+ dtdHandler.unparsedEntityDecl(name, publicId, systemId, notationName);
+ }
+ }
+
+ // ==== ContentHandler
+
+ /**
+ * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
+ */
+ public void setDocumentLocator(Locator locator) {
+ delegate.setDocumentLocator(locator);
+ }
+
+ /**
+ * @see org.xml.sax.ContentHandler#startDocument()
+ */
+ public void startDocument() throws SAXException {
+ delegate.startDocument();
+ }
+
+ /**
+ * @see org.xml.sax.ContentHandler#endDocument()
+ */
+ public void endDocument() throws SAXException {
+ delegate.endDocument();
+ }
+
+ /**
+ * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String, java.lang.String)
+ */
+ public void startPrefixMapping(String prefix, String uri) throws SAXException {
+ delegate.startPrefixMapping(prefix, uri);
+ }
+
+ /**
+ * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)
+ */
+ public void endPrefixMapping(String prefix) throws SAXException {
+ delegate.endPrefixMapping(prefix);
+ }
+
+ /**
+ * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
+ */
+ public void startElement(String uri, String localName, String qName,
+ Attributes atts) throws SAXException {
+ delegate.startElement(uri, localName, qName, atts);
+ }
+
+ /**
+ * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
+ */
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ delegate.endElement(uri, localName, qName);
+ }
+
+ /**
+ * @see org.xml.sax.ContentHandler#characters(char[], int, int)
+ */
+ public void characters(char[] ch, int start, int length) throws SAXException {
+ delegate.characters(ch, start, length);
+ }
+
+ /**
+ * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
+ */
+ public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
+ delegate.ignorableWhitespace(ch, start, length);
+ }
+
+ /**
+ * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String)
+ */
+ public void processingInstruction(String target, String data) throws SAXException {
+ delegate.processingInstruction(target, data);
+ }
+
+ /**
+ * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
+ */
+ public void skippedEntity(String name) throws SAXException {
+ delegate.skippedEntity(name);
+ }
+
+ // ==== LexicalHandler
+
+ /**
+ * @see org.xml.sax.ext.LexicalHandler#startDTD(java.lang.String, java.lang.String, java.lang.String)
+ */
+ public void startDTD(String name, String publicId, String systemId) throws SAXException {
+ if (lexicalHandler != null) {
+ lexicalHandler.startDTD(name, publicId, systemId);
+ }
+
+ }
+
+ /**
+ * @see org.xml.sax.ext.LexicalHandler#endDTD()
+ */
+ public void endDTD() throws SAXException {
+ if (lexicalHandler != null) {
+ lexicalHandler.endDTD();
+ }
+ }
+
+ /**
+ * @see org.xml.sax.ext.LexicalHandler#startEntity(java.lang.String)
+ */
+ public void startEntity(String name) throws SAXException {
+ if (lexicalHandler != null) {
+ lexicalHandler.startEntity(name);
+ }
+ }
+
+ /**
+ * @see org.xml.sax.ext.LexicalHandler#endEntity(java.lang.String)
+ */
+ public void endEntity(String name) throws SAXException {
+ if (lexicalHandler != null) {
+ lexicalHandler.endEntity(name);
+ }
+ }
+
+ /**
+ * @see org.xml.sax.ext.LexicalHandler#startCDATA()
+ */
+ public void startCDATA() throws SAXException {
+ if (lexicalHandler != null) {
+ lexicalHandler.startCDATA();
+ }
+ }
+
+ /**
+ * @see org.xml.sax.ext.LexicalHandler#endCDATA()
+ */
+ public void endCDATA() throws SAXException {
+ if (lexicalHandler != null) {
+ lexicalHandler.endCDATA();
+ }
+ }
+
+ /**
+ * @see org.xml.sax.ext.LexicalHandler#comment(char[], int, int)
+ */
+ public void comment(char[] ch, int start, int length) throws SAXException {
+ if (lexicalHandler != null) {
+ lexicalHandler.comment(ch, start, length);
+ }
+ }
+
+ // ==== ErrorHandler
+
+ /**
+ * @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException)
+ */
+ public void warning(SAXParseException exception) throws SAXException {
+ if (errorHandler != null) {
+ errorHandler.warning(exception);
+ }
+ }
+
+ /**
+ * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException)
+ */
+ public void error(SAXParseException exception) throws SAXException {
+ if (errorHandler != null) {
+ errorHandler.error(exception);
+ }
+ }
+
+ /**
+ * @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException)
+ */
+ public void fatalError(SAXParseException exception) throws SAXException {
+ if (errorHandler != null) {
+ errorHandler.fatalError(exception);
+ }
+ }
+
+}