1.1 --- a/openide.util/src/org/openide/xml/XMLUtil.java Wed Jan 09 16:58:12 2008 +0000
1.2 +++ b/openide.util/src/org/openide/xml/XMLUtil.java Thu Jan 10 13:45:24 2008 +0000
1.3 @@ -45,6 +45,8 @@
1.4 import java.io.IOException;
1.5 import java.io.OutputStream;
1.6 import java.io.StringReader;
1.7 +import java.util.HashSet;
1.8 +import java.util.Set;
1.9 import javax.xml.parsers.DocumentBuilder;
1.10 import javax.xml.parsers.DocumentBuilderFactory;
1.11 import javax.xml.parsers.ParserConfigurationException;
1.12 @@ -58,6 +60,7 @@
1.13 import javax.xml.transform.stream.StreamResult;
1.14 import javax.xml.transform.stream.StreamSource;
1.15 import org.openide.util.Lookup;
1.16 +import org.w3c.dom.CDATASection;
1.17 import org.w3c.dom.DOMException;
1.18 import org.w3c.dom.DOMImplementation;
1.19 import org.w3c.dom.Document;
1.20 @@ -351,6 +354,15 @@
1.21 * Writes a DOM document to a stream.
1.22 * The precise output format is not guaranteed but this method will attempt to indent it sensibly.
1.23 *
1.24 + * <p class="nonnormative"><b>Important</b>: There might be some problems with
1.25 + * <code><![CDATA[ ]]></code> sections in the DOM tree you pass into this method. Specifically,
1.26 + * some CDATA sections my not be written as CDATA section or may be merged with
1.27 + * other CDATA section at the same level. Also if plain text nodes are mixed with
1.28 + * CDATA sections at the same level all text is likely to end up in one big CDATA section.
1.29 + * <br/>
1.30 + * For nodes that only have one CDATA section this method should work fine.
1.31 + * </p>
1.32 + *
1.33 * @param doc DOM document to be written
1.34 * @param out data sink
1.35 * @param enc XML-defined encoding name (e.g. "UTF-8")
1.36 @@ -403,6 +415,18 @@
1.37 t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, dt.getSystemId());
1.38 }
1.39 t.setOutputProperty(OutputKeys.ENCODING, enc);
1.40 +
1.41 + // See #123816
1.42 + Set<String> cdataQNames = new HashSet<String>();
1.43 + collectCDATASections(doc2, cdataQNames);
1.44 + if (cdataQNames.size() > 0) {
1.45 + StringBuilder cdataSections = new StringBuilder();
1.46 + for(String s : cdataQNames) {
1.47 + cdataSections.append(s).append(' '); //NOI18N
1.48 + }
1.49 + t.setOutputProperty(OutputKeys.CDATA_SECTION_ELEMENTS, cdataSections.toString());
1.50 + }
1.51 +
1.52 Source source = new DOMSource(doc2);
1.53 Result result = new StreamResult(out);
1.54 t.transform(source, result);
1.55 @@ -413,6 +437,25 @@
1.56 }
1.57 }
1.58
1.59 + private static void collectCDATASections(Node node, Set<String> cdataQNames) {
1.60 + if (node instanceof CDATASection) {
1.61 + Node parent = node.getParentNode();
1.62 + if (parent != null) {
1.63 + String uri = parent.getNamespaceURI();
1.64 + if (uri != null) {
1.65 + cdataQNames.add("{" + uri + "}" + parent.getNodeName()); //NOI18N
1.66 + } else {
1.67 + cdataQNames.add(parent.getNodeName());
1.68 + }
1.69 + }
1.70 + }
1.71 +
1.72 + NodeList children = node.getChildNodes();
1.73 + for(int i = 0; i < children.getLength(); i++) {
1.74 + collectCDATASections(children.item(i), cdataQNames);
1.75 + }
1.76 + }
1.77 +
1.78 /**
1.79 * Escape passed string as XML attibute value
1.80 * (<code><</code>, <code>&</code>, <code>'</code> and <code>"</code>