diff options
Diffstat (limited to 'gnu/xml/transform/TransformerImpl.java')
-rw-r--r-- | gnu/xml/transform/TransformerImpl.java | 209 |
1 files changed, 199 insertions, 10 deletions
diff --git a/gnu/xml/transform/TransformerImpl.java b/gnu/xml/transform/TransformerImpl.java index c0af0fca4..a36aa6173 100644 --- a/gnu/xml/transform/TransformerImpl.java +++ b/gnu/xml/transform/TransformerImpl.java @@ -15,8 +15,8 @@ General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -02111-1307 USA. +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and @@ -48,7 +48,12 @@ import java.net.UnknownServiceException; import java.net.URL; import java.net.URLConnection; import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; import java.util.Properties; +import java.util.StringTokenizer; +import javax.xml.namespace.QName; import javax.xml.transform.ErrorListener; import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; @@ -101,7 +106,7 @@ class TransformerImpl if (stylesheet != null) { // Set up parameter context for this transformer - stylesheet.bindings.push(false); + stylesheet.bindings.push(Bindings.PARAM); } } @@ -241,8 +246,10 @@ class TransformerImpl boolean standalone = "yes".equals(outputProperties.getProperty(OutputKeys.STANDALONE)); String mediaType = outputProperties.getProperty(OutputKeys.MEDIA_TYPE); - // TODO cdata-section-elements - // TODO indent + String cdataSectionElements = + outputProperties.getProperty(OutputKeys.CDATA_SECTION_ELEMENTS); + boolean indent = + "yes".equals(outputProperties.getProperty(OutputKeys.INDENT)); if (created) { // Discover document element @@ -309,6 +316,44 @@ class TransformerImpl { parent.setUserData("media-type", mediaType, stylesheet); } + if (cdataSectionElements != null) + { + List list = new LinkedList(); + StringTokenizer st = new StringTokenizer(cdataSectionElements); + while (st.hasMoreTokens()) + { + String name = st.nextToken(); + String localName = name; + String uri = null; + String prefix = null; + int ci = name.indexOf(':'); + if (ci != -1) + { + // Use namespaces defined on xsl:output node to resolve + // namespaces for QName + prefix = name.substring(0, ci); + localName = name.substring(ci + 1); + uri = stylesheet.output.lookupNamespaceURI(prefix); + } + list.add(new QName(uri, localName, prefix)); + } + if (!list.isEmpty()) + { + Document resultDoc = (parent instanceof Document) ? + (Document) parent : + parent.getOwnerDocument(); + convertCdataSectionElements(resultDoc, parent, list); + } + } + if (indent) + { + parent.normalize(); + strip(parent); + Document resultDoc = (parent instanceof Document) ? + (Document) parent : + parent.getOwnerDocument(); + reindent(resultDoc, parent, 0); + } // Render result to the target device if (outputTarget instanceof DOMResult) { @@ -407,12 +452,21 @@ class TransformerImpl } parent.removeChild(node); } - if (nt == Node.TEXT_NODE) // CDATA sections ? + if (nt == Node.TEXT_NODE || nt == Node.CDATA_SECTION_NODE) { if (!stylesheet.isPreserved((Text) node)) { node.getParentNode().removeChild(node); } + else + { + String text = node.getNodeValue(); + String stripped = text.trim(); + if (!text.equals(stripped)) + { + node.setNodeValue(stripped); + } + } } else { @@ -505,7 +559,7 @@ class TransformerImpl { if (stylesheet != null) { - stylesheet.bindings.set(name, value, false); + stylesheet.bindings.set(new QName(null, name), value, Bindings.PARAM); } } @@ -513,7 +567,7 @@ class TransformerImpl { if (stylesheet != null) { - return stylesheet.bindings.get(name, null, 1, 1); + return stylesheet.bindings.get(new QName(null, name), null, 1, 1); } return null; } @@ -522,8 +576,8 @@ class TransformerImpl { if (stylesheet != null) { - stylesheet.bindings.pop(false); - stylesheet.bindings.push(false); + stylesheet.bindings.pop(Bindings.PARAM); + stylesheet.bindings.push(Bindings.PARAM); } } @@ -577,4 +631,139 @@ class TransformerImpl return errorListener; } + static final String INDENT_WHITESPACE = " "; + + /* + * Apply indent formatting to the given tree. + */ + void reindent(Document doc, Node node, int offset) + { + if (node.hasChildNodes()) + { + boolean markupContent = false; + boolean textContent = false; + List children = new LinkedList(); + Node ctx = node.getFirstChild(); + while (ctx != null) + { + switch (ctx.getNodeType()) + { + case Node.ELEMENT_NODE: + case Node.PROCESSING_INSTRUCTION_NODE: + case Node.DOCUMENT_TYPE_NODE: + markupContent = true; + break; + case Node.TEXT_NODE: + case Node.CDATA_SECTION_NODE: + case Node.ENTITY_REFERENCE_NODE: + case Node.COMMENT_NODE: + textContent = true; + break; + } + children.add(ctx); + ctx = ctx.getNextSibling(); + } + if (markupContent) + { + if (textContent) + { + // XXX handle mixed content differently? + } + int nodeType = node.getNodeType(); + if (nodeType == Node.DOCUMENT_NODE) + { + for (Iterator i = children.iterator(); i.hasNext(); ) + { + ctx = (Node) i.next(); + reindent(doc, ctx, offset + 1); + } + } + else + { + StringBuffer buf = new StringBuffer(); + buf.append('\n'); + for (int i = 0; i < offset + 1; i++) + { + buf.append(INDENT_WHITESPACE); + } + String ws = buf.toString(); + for (Iterator i = children.iterator(); i.hasNext(); ) + { + ctx = (Node) i.next(); + node.insertBefore(doc.createTextNode(ws), ctx); + reindent(doc, ctx, offset + 1); + } + buf = new StringBuffer(); + buf.append('\n'); + ws = buf.toString(); + for (int i = 0; i < offset; i++) + { + buf.append(INDENT_WHITESPACE); + } + node.appendChild(doc.createTextNode(ws)); + } + } + } + } + + /** + * Converts the text node children of any cdata-section-elements in the + * tree to CDATA section nodes. + */ + void convertCdataSectionElements(Document doc, Node node, List list) + { + if (node.getNodeType() == Node.ELEMENT_NODE) + { + boolean match = false; + for (Iterator i = list.iterator(); i.hasNext(); ) + { + QName qname = (QName) i.next(); + if (match(qname, node)) + { + match = true; + break; + } + } + if (match) + { + Node ctx = node.getFirstChild(); + while (ctx != null) + { + if (ctx.getNodeType() == Node.TEXT_NODE) + { + Node cdata = doc.createCDATASection(ctx.getNodeValue()); + node.replaceChild(cdata, ctx); + ctx = cdata; + } + ctx = ctx.getNextSibling(); + } + } + } + Node ctx = node.getFirstChild(); + while (ctx != null) + { + if (ctx.hasChildNodes()) + { + convertCdataSectionElements(doc, ctx, list); + } + ctx = ctx.getNextSibling(); + } + } + + boolean match(QName qname, Node node) + { + String ln1 = qname.getLocalPart(); + String ln2 = node.getLocalName(); + if (ln2 == null) + { + return ln1.equals(node.getNodeName()); + } + else + { + String uri1 = qname.getNamespaceURI(); + String uri2 = node.getNamespaceURI(); + return (uri1.equals(uri2) && ln1.equals(ln2)); + } + } + } |