123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- /*
- * 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.util;
-
- import java.util.List;
- import java.util.Map;
- import java.util.Stack;
-
- 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.
- * <p>
- * Part of the code here copied and adapted from Apache Xalan-J,
- * src/org/apache/xalan/xsltc/trax/DOM2SAX.java
- */
- public class DOM2SAX {
-
- private static final String EMPTYSTRING = "";
- private static final String XMLNS_PREFIX = "xmlns";
-
- private ContentHandler contentHandler;
- private LexicalHandler lexicalHandler;
-
- private Map prefixes = new java.util.HashMap();
-
- /**
- * Main constructor
- * @param handler the ContentHandler to send SAX events to
- */
- public DOM2SAX(ContentHandler handler) {
- this.contentHandler = handler;
- if (handler instanceof LexicalHandler) {
- this.lexicalHandler = (LexicalHandler)handler;
- }
- }
-
- /**
- * Writes the given document using the given ContentHandler.
- * @param doc DOM document
- * @param fragment if false no startDocument() and endDocument() calls are issued.
- * @throws SAXException In case of a problem while writing XML
- */
- public void writeDocument(Document doc, boolean fragment) throws SAXException {
- if (!fragment) {
- contentHandler.startDocument();
- }
- for (Node n = doc.getFirstChild(); n != null;
- n = n.getNextSibling()) {
- writeNode(n);
- }
- if (!fragment) {
- contentHandler.endDocument();
- }
- }
-
- /**
- * Writes the given fragment using the given ContentHandler.
- * @param node DOM node
- * @throws SAXException In case of a problem while writing XML
- */
- public void writeFragment(Node node) throws SAXException {
- writeNode(node);
- }
-
- /**
- * Begin the scope of namespace prefix. Forward the event to the SAX handler
- * only if the prefix is unknown or it is mapped to a different URI.
- */
- private boolean startPrefixMapping(String prefix, String uri)
- throws SAXException {
- boolean pushed = true;
- Stack uriStack = (Stack)prefixes.get(prefix);
-
- if (uriStack != null) {
- if (uriStack.isEmpty()) {
- contentHandler.startPrefixMapping(prefix, uri);
- uriStack.push(uri);
- } else {
- final String lastUri = (String) uriStack.peek();
- if (!lastUri.equals(uri)) {
- contentHandler.startPrefixMapping(prefix, uri);
- uriStack.push(uri);
- } else {
- pushed = false;
- }
- }
- } else {
- contentHandler.startPrefixMapping(prefix, uri);
- uriStack = new Stack();
- prefixes.put(prefix, uriStack);
- uriStack.push(uri);
- }
- return pushed;
- }
-
- /*
- * End the scope of a name prefix by popping it from the stack and passing
- * the event to the SAX Handler.
- */
- private void endPrefixMapping(String prefix) throws SAXException {
- final Stack uriStack = (Stack)prefixes.get(prefix);
-
- if (uriStack != null) {
- contentHandler.endPrefixMapping(prefix);
- uriStack.pop();
- }
- }
-
- /**
- * If the DOM was created using a DOM 1.0 API, the local name may be null.
- * If so, get the local name from the qualified name before generating the
- * SAX event.
- */
- private static String getLocalName(Node node) {
- final String localName = node.getLocalName();
-
- if (localName == null) {
- final String qname = node.getNodeName();
- final int col = qname.lastIndexOf(':');
- return (col > 0) ? qname.substring(col + 1) : qname;
- }
- return localName;
- }
-
- /**
- * Writes a node using the given writer.
- * @param node node to serialize
- * @throws SAXException In case of a problem while writing XML
- */
- private void writeNode(Node node)
- throws SAXException {
- if (node == null) {
- return;
- }
-
- switch (node.getNodeType()) {
- case Node.ATTRIBUTE_NODE: // handled by ELEMENT_NODE
- case Node.DOCUMENT_FRAGMENT_NODE:
- case Node.DOCUMENT_TYPE_NODE:
- case Node.ENTITY_NODE:
- case Node.ENTITY_REFERENCE_NODE:
- case Node.NOTATION_NODE:
- // These node types are ignored!!!
- break;
- case Node.CDATA_SECTION_NODE:
- final String cdata = node.getNodeValue();
- if (lexicalHandler != null) {
- lexicalHandler.startCDATA();
- contentHandler.characters(cdata.toCharArray(), 0, cdata.length());
- lexicalHandler.endCDATA();
- } else {
- // in the case where there is no lex handler, we still
- // want the text of the cdate to make its way through.
- contentHandler.characters(cdata.toCharArray(), 0, cdata.length());
- }
- break;
-
- case Node.COMMENT_NODE: // should be handled!!!
- if (lexicalHandler != null) {
- final String value = node.getNodeValue();
- lexicalHandler.comment(value.toCharArray(), 0, value.length());
- }
- break;
- case Node.DOCUMENT_NODE:
- contentHandler.startDocument();
- Node next = node.getFirstChild();
- while (next != null) {
- writeNode(next);
- next = next.getNextSibling();
- }
- contentHandler.endDocument();
- break;
-
- case Node.ELEMENT_NODE:
- String prefix;
- List pushedPrefixes = new java.util.ArrayList();
- final AttributesImpl attrs = new AttributesImpl();
- final NamedNodeMap map = node.getAttributes();
- final int length = map.getLength();
-
- // Process all namespace declarations
- for (int i = 0; i < length; i++) {
- final Node attr = map.item(i);
- final String qnameAttr = attr.getNodeName();
-
- // Ignore everything but NS declarations here
- if (qnameAttr.startsWith(XMLNS_PREFIX)) {
- final String uriAttr = attr.getNodeValue();
- final int colon = qnameAttr.lastIndexOf(':');
- prefix = (colon > 0) ? qnameAttr.substring(colon + 1)
- : EMPTYSTRING;
- if (startPrefixMapping(prefix, uriAttr)) {
- pushedPrefixes.add(prefix);
- }
- }
- }
-
- // Process all other attributes
- for (int i = 0; i < length; i++) {
- final Node attr = map.item(i);
- final String qnameAttr = attr.getNodeName();
-
- // Ignore NS declarations here
- if (!qnameAttr.startsWith(XMLNS_PREFIX)) {
- final String uriAttr = attr.getNamespaceURI();
-
- // Uri may be implicitly declared
- if (uriAttr != null) {
- final int colon = qnameAttr.lastIndexOf(':');
- prefix = (colon > 0) ? qnameAttr.substring(0, colon)
- : EMPTYSTRING;
- if (startPrefixMapping(prefix, uriAttr)) {
- pushedPrefixes.add(prefix);
- }
- }
-
- // Add attribute to list
- attrs.addAttribute(attr.getNamespaceURI(),
- getLocalName(attr), qnameAttr, XMLUtil.CDATA, attr
- .getNodeValue());
- }
- }
-
- // Now process the element itself
- final String qname = node.getNodeName();
- final String uri = node.getNamespaceURI();
- final String localName = getLocalName(node);
-
- // Uri may be implicitly declared
- if (uri != null) {
- final int colon = qname.lastIndexOf(':');
- prefix = (colon > 0) ? qname.substring(0, colon) : EMPTYSTRING;
- if (startPrefixMapping(prefix, uri)) {
- pushedPrefixes.add(prefix);
- }
- }
-
- // Generate SAX event to start element
- contentHandler.startElement(uri, localName, qname, attrs);
-
- // Traverse all child nodes of the element (if any)
- next = node.getFirstChild();
- while (next != null) {
- writeNode(next);
- next = next.getNextSibling();
- }
-
- // Generate SAX event to close element
- contentHandler.endElement(uri, localName, qname);
-
- // Generate endPrefixMapping() for all pushed prefixes
- final int nPushedPrefixes = pushedPrefixes.size();
- for (Object pushedPrefixe : pushedPrefixes) {
- endPrefixMapping((String) pushedPrefixe);
- }
- break;
-
- case Node.PROCESSING_INSTRUCTION_NODE:
- contentHandler.processingInstruction(node.getNodeName(), node.getNodeValue());
- break;
-
- case Node.TEXT_NODE:
- final String data = node.getNodeValue();
- contentHandler.characters(data.toCharArray(), 0, data.length());
- break;
- default:
- //nop
- }
- }
-
-
- }
|