You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-commits@xmlgraphics.apache.org by ca...@apache.org on 2008/06/02 03:37:54 UTC
svn commit: r662304 - in /xmlgraphics/batik/trunk: ./
sources/org/apache/batik/apps/svgbrowser/ sources/org/apache/batik/bridge/
sources/org/apache/batik/dom/util/ sources/org/apache/batik/script/
sources/org/apache/batik/script/rhino/
Author: cam
Date: Sun Jun 1 18:37:54 2008
New Revision: 662304
URL: http://svn.apache.org/viewvc?rev=662304&view=rev
Log:
1. Add support for the printNode() script function.
2. Make prompt() return a proper ECMAScript String value.
3. Fix up the serialization code so that the output will be namespace-
well-formed, regardless of the prefixes and namespace declarations
in the document.
4. Create a DocumentType node for documents that have a DTD.
Modified:
xmlgraphics/batik/trunk/CHANGES
xmlgraphics/batik/trunk/sources/org/apache/batik/apps/svgbrowser/XMLPreferenceManager.java
xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/BaseScriptingEnvironment.java
xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/ScriptingEnvironment.java
xmlgraphics/batik/trunk/sources/org/apache/batik/dom/util/DOMUtilities.java
xmlgraphics/batik/trunk/sources/org/apache/batik/dom/util/SAXDocumentFactory.java
xmlgraphics/batik/trunk/sources/org/apache/batik/script/Window.java
xmlgraphics/batik/trunk/sources/org/apache/batik/script/rhino/WindowWrapper.java
Modified: xmlgraphics/batik/trunk/CHANGES
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/CHANGES?rev=662304&r1=662303&r2=662304&view=diff
==============================================================================
--- xmlgraphics/batik/trunk/CHANGES (original)
+++ xmlgraphics/batik/trunk/CHANGES Sun Jun 1 18:37:54 2008
@@ -11,6 +11,22 @@
44590, 44966
+2. New features
+
+ * Support for the printNode() script function.
+
+3. Improvements
+
+ * DocumentType nodes are now created for XML documents where one was
+ supplied in the markup (although only the name, publicId and systemId
+ properties of the DocumentType object are filled in).
+
+4. Bug fixes
+
+ * Better DOM serialization code.
+ * The prompt() script function now returns a proper ECMAScript String
+ value instead of an object.
+
1.7beta1 -> 1.7
---------------
Modified: xmlgraphics/batik/trunk/sources/org/apache/batik/apps/svgbrowser/XMLPreferenceManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/apache/batik/apps/svgbrowser/XMLPreferenceManager.java?rev=662304&r1=662303&r2=662304&view=diff
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/apps/svgbrowser/XMLPreferenceManager.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/apps/svgbrowser/XMLPreferenceManager.java Sun Jun 1 18:37:54 2008
@@ -169,7 +169,11 @@
String v = (String)m.get(n);
w.write("<property name=\"" + n + "\">");
- w.write(DOMUtilities.contentToString(v));
+ try {
+ w.write(DOMUtilities.contentToString(v, false));
+ } catch (IOException ex) {
+ // unlikely to happen
+ }
w.write("</property>\n");
}
Modified: xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/BaseScriptingEnvironment.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/BaseScriptingEnvironment.java?rev=662304&r1=662303&r2=662304&view=diff
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/BaseScriptingEnvironment.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/BaseScriptingEnvironment.java Sun Jun 1 18:37:54 2008
@@ -784,6 +784,13 @@
}
/**
+ * Serializes the given node.
+ */
+ public String printNode(Node n) {
+ return null;
+ }
+
+ /**
* Gets data from the given URI.
* @param uri The URI where the data is located.
* @param h A handler called when the data is available.
Modified: xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/ScriptingEnvironment.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/ScriptingEnvironment.java?rev=662304&r1=662303&r2=662304&view=diff
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/ScriptingEnvironment.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/ScriptingEnvironment.java Sun Jun 1 18:37:54 2008
@@ -26,6 +26,7 @@
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
+import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.URL;
@@ -979,6 +980,20 @@
}
/**
+ * Serializes the given node.
+ */
+ public String printNode(Node n) {
+ try {
+ Writer writer = new StringWriter();
+ DOMUtilities.writeNode(n, writer);
+ writer.close();
+ return writer.toString();
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ /**
* Implements {@link
* org.apache.batik.script.Window#getURL(String,org.apache.batik.script.Window.URLResponseHandler)}.
*/
Modified: xmlgraphics/batik/trunk/sources/org/apache/batik/dom/util/DOMUtilities.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/apache/batik/dom/util/DOMUtilities.java?rev=662304&r1=662303&r2=662304&view=diff
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/dom/util/DOMUtilities.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/dom/util/DOMUtilities.java Sun Jun 1 18:37:54 2008
@@ -23,10 +23,12 @@
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
+import org.apache.batik.dom.AbstractDocument;
import org.apache.batik.xml.XMLUtilities;
import org.w3c.dom.Attr;
@@ -46,98 +48,247 @@
* @version $Id$
*/
public class DOMUtilities extends XMLUtilities {
+
/**
- * Do not need to be instantiated.
+ * Does not need to be instantiated.
*/
protected DOMUtilities() {
}
+
+ private static class NSMap {
+ private String prefix;
+ private String ns; // "" is used for no namespace
+ private NSMap next;
+ private int nextPrefixNumber;
+
+ public NSMap declare(String prefix, String ns) {
+ NSMap m = new NSMap();
+ m.prefix = prefix;
+ m.ns = ns;
+ m.next = this;
+ m.nextPrefixNumber = this.nextPrefixNumber;
+ return m;
+ }
+
+ public String getNewPrefix() {
+ String prefix;
+ do {
+ prefix = "a" + nextPrefixNumber++;
+ } while (getNamespace(prefix) != null);
+ return prefix;
+ }
+
+ public String getNamespace(String prefix) {
+ for (NSMap m = this; m.next != null; m = m.next) {
+ if (m.prefix.equals(prefix)) {
+ return m.ns;
+ }
+ }
+ return null;
+ }
+
+ public String getPrefixForElement(String ns) {
+ for (NSMap m = this; m.next != null; m = m.next) {
+ if (ns.equals(m.ns)) {
+ return m.prefix;
+ }
+ }
+ return null;
+ }
+
+ public String getPrefixForAttr(String ns) {
+ for (NSMap m = this; m.next != null; m = m.next) {
+ if (ns.equals(m.ns) && !m.prefix.equals("")) {
+ return m.prefix;
+ }
+ }
+ return null;
+ }
+ }
/**
- * Writes the given document using the given writer.
+ * Serializes the specified <code>Document</code>, writing it to the given
+ * <code>Writer</code>.
*/
public static void writeDocument(Document doc, Writer w) throws IOException {
+ AbstractDocument d = (AbstractDocument) doc;
+ if (doc.getDocumentElement() == null) {
+ throw new IOException("No document element");
+ }
+ NSMap m = new NSMap();
for (Node n = doc.getFirstChild();
n != null;
n = n.getNextSibling()) {
- writeNode(n, w);
+ writeNode(n, w, m, "1.1".equals(d.getXmlVersion()));
}
}
- /**
- * Writes a node using the given writer.
- */
- public static void writeNode(Node n, Writer w) throws IOException {
+ protected static void writeNode(Node n, Writer w, NSMap m, boolean isXML11)
+ throws IOException {
switch (n.getNodeType()) {
- case Node.ELEMENT_NODE:
- w.write("<");
- w.write(n.getNodeName());
+ case Node.ELEMENT_NODE: {
+ if (n.hasAttributes()) {
+ NamedNodeMap attr = n.getAttributes();
+ int len = attr.getLength();
+ for (int i = 0; i < len; i++) {
+ Attr a = (Attr)attr.item(i);
+ String name = a.getNodeName();
+ if (name.startsWith("xmlns")) {
+ if (name.length() == 5) {
+ m = m.declare("", a.getNodeValue());
+ } else {
+ String prefix = name.substring(6);
+ m = m.declare(prefix, a.getNodeValue());
+ }
+ }
+ }
+ }
+
+ w.write('<');
+ String ns = n.getNamespaceURI();
+ String tagName;
+ if (ns == null) {
+ tagName = n.getNodeName();
+ w.write(tagName);
+ if (!"".equals(m.getNamespace(""))) {
+ w.write(" xmlns=\"\"");
+ m = m.declare("", "");
+ }
+ } else {
+ String prefix = n.getPrefix();
+ if (prefix == null) {
+ prefix = "";
+ }
+ if (ns.equals(m.getNamespace(prefix))) {
+ tagName = n.getNodeName();
+ w.write(tagName);
+ } else {
+ prefix = m.getPrefixForElement(ns);
+ if (prefix == null) {
+ prefix = m.getNewPrefix();
+ tagName = prefix + ':' + n.getLocalName();
+ w.write(tagName + " xmlns:" + prefix + "=\""
+ + contentToString(ns, isXML11) + '"');
+ m = m.declare(prefix, ns);
+ } else {
+ if (prefix.equals("")) {
+ tagName = n.getLocalName();
+ } else {
+ tagName = prefix + ':' + n.getLocalName();
+ }
+ w.write(tagName);
+ }
+ }
+ }
if (n.hasAttributes()) {
NamedNodeMap attr = n.getAttributes();
int len = attr.getLength();
for (int i = 0; i < len; i++) {
Attr a = (Attr)attr.item(i);
- w.write(" ");
- w.write(a.getNodeName());
- w.write("=\"");
- w.write(contentToString(a.getNodeValue()));
- w.write("\"");
+ String name = a.getNodeName();
+ String prefix = a.getPrefix();
+ String ans = a.getNamespaceURI();
+ if (ans != null &&
+ !("xmlns".equals(prefix) || name.equals("xmlns"))) {
+ if (prefix != null
+ && !ans.equals(m.getNamespace(prefix))
+ || prefix == null) {
+ prefix = m.getPrefixForAttr(ans);
+ if (prefix == null) {
+ prefix = m.getNewPrefix();
+ m = m.declare(prefix, ans);
+ }
+ name = prefix + ':' + a.getLocalName();
+ }
+ }
+ w.write(' ' + name + "=\""
+ + contentToString(a.getNodeValue(), isXML11)
+ + '"');
}
}
Node c = n.getFirstChild();
if (c != null) {
- w.write(">");
- for (; c != null;
- c = c.getNextSibling()) {
- writeNode(c, w);
- }
- w.write("</");
- w.write(n.getNodeName());
- w.write(">");
+ w.write('>');
+ do {
+ writeNode(c, w, m, isXML11);
+ c = c.getNextSibling();
+ } while (c != null);
+ w.write("</" + tagName + '>');
} else {
w.write("/>");
}
break;
+ }
case Node.TEXT_NODE:
- w.write(contentToString(n.getNodeValue()));
+ w.write(contentToString(n.getNodeValue(), isXML11));
break;
- case Node.CDATA_SECTION_NODE:
- w.write("<![CDATA[");
- w.write(n.getNodeValue());
- w.write("]]>");
+ case Node.CDATA_SECTION_NODE: {
+ String data = n.getNodeValue();
+ if (data.indexOf("]]>") != -1) {
+ throw new IOException("Unserializable CDATA section node");
+ }
+ w.write("<![CDATA["
+ + assertValidCharacters(data, isXML11)
+ + "]]>");
break;
+ }
case Node.ENTITY_REFERENCE_NODE:
- w.write("&");
- w.write(n.getNodeName());
- w.write(";");
+ w.write('&' + n.getNodeName() + ';');
break;
- case Node.PROCESSING_INSTRUCTION_NODE:
- w.write("<?");
- w.write(n.getNodeName());
- // TD: Bug #19392
- w.write(" ");
- w.write(n.getNodeValue());
- w.write("?>");
+ case Node.PROCESSING_INSTRUCTION_NODE: {
+ String target = n.getNodeName();
+ String data = n.getNodeValue();
+ if (target.equalsIgnoreCase("xml")
+ || target.indexOf(':') != -1
+ || data.indexOf("?>") != -1) {
+ throw new
+ IOException("Unserializable processing instruction node");
+ }
+ w.write("<?" + target + ' ' + data + "?>");
break;
- case Node.COMMENT_NODE:
+ }
+ case Node.COMMENT_NODE: {
w.write("<!--");
- w.write(n.getNodeValue());
+ String data = n.getNodeValue();
+ int len = data.length();
+ if (len != 0 && data.charAt(len - 1) == '-'
+ || data.indexOf("--") != -1) {
+ throw new IOException("Unserializable comment node");
+ }
+ w.write(data);
w.write("-->");
break;
+ }
case Node.DOCUMENT_TYPE_NODE: {
DocumentType dt = (DocumentType)n;
- w.write ("<!DOCTYPE ");
- w.write (n.getOwnerDocument().getDocumentElement().getNodeName());
+ w.write("<!DOCTYPE "
+ + n.getOwnerDocument().getDocumentElement().getNodeName());
String pubID = dt.getPublicId();
if (pubID != null) {
- w.write (" PUBLIC \"" + dt.getNodeName() + "\" \"" +
- pubID + "\">");
- } else {
- String sysID = dt.getSystemId();
- if (sysID != null)
- w.write (" SYSTEM \"" + sysID + "\">");
+ char q = getUsableQuote(pubID);
+ if (q == 0) {
+ throw new IOException("Unserializable DOCTYPE node");
+ }
+ w.write(" PUBLIC " + q + pubID + q);
}
+ String sysID = dt.getSystemId();
+ if (sysID != null) {
+ char q = getUsableQuote(sysID);
+ if (q == 0) {
+ throw new IOException("Unserializable DOCTYPE node");
+ }
+ if (pubID == null) {
+ w.write(" SYSTEM");
+ }
+ w.write(" " + q + sysID + q);
+ }
+ String subset = dt.getInternalSubset();
+ if (subset != null) {
+ w.write('[' + subset + ']');
+ }
+ w.write('>');
break;
}
default:
@@ -146,6 +297,47 @@
}
/**
+ * Writes a node using the given writer.
+ */
+ public static void writeNode(Node n, Writer w) throws IOException {
+ if (n.getNodeType() == Node.DOCUMENT_NODE) {
+ writeDocument((Document) n, w);
+ } else {
+ AbstractDocument d = (AbstractDocument) n.getOwnerDocument();
+ writeNode(n, w, new NSMap(),
+ d == null ? false : "1.1".equals(d.getXmlVersion()));
+ }
+ }
+
+ /**
+ * Returns the quote character to use when quoting the specified string.
+ * If the string contains both single and double quotes, then 0 will be
+ * returned.
+ */
+ private static char getUsableQuote(String s) {
+ char ret = 0;
+ int i = s.length() - 1;
+ while (i >= 0) {
+ char c = s.charAt(i);
+ if (c == '"') {
+ if (ret == 0) {
+ ret = '\'';
+ } else {
+ return 0;
+ }
+ } else if (c == '\'') {
+ if (ret == 0) {
+ ret = '"';
+ } else {
+ return 0;
+ }
+ }
+ i--;
+ }
+ return ret == 0 ? '"' : ret;
+ }
+
+ /**
* Serializes the given DOM node using {@link #writeNode(Node,Writer)}
* and returns the XML as a String.
*
@@ -164,15 +356,36 @@
return writer.toString();
}
+ protected static String assertValidCharacters(String s, boolean isXML11)
+ throws IOException {
+
+ int len = s.length();
+ for (int i = 0; i < len; i++) {
+ char c = s.charAt(i);
+ if (!isXML11 && !isXMLCharacter(c)
+ || isXML11 && !isXML11Character(c)) {
+ throw new IOException("Invalid character");
+ }
+ }
+ return s;
+ }
+
/**
* Returns the given content value transformed to replace invalid
* characters with entities.
*/
- public static String contentToString(String s) {
- StringBuffer result = new StringBuffer( s.length() );
+ public static String contentToString(String s, boolean isXML11)
+ throws IOException {
+
+ StringBuffer result = new StringBuffer(s.length());
- for (int i = 0; i < s.length(); i++) {
+ int len = s.length();
+ for (int i = 0; i < len; i++) {
char c = s.charAt(i);
+ if (!isXML11 && !isXMLCharacter(c)
+ || isXML11 && !isXML11Character(c)) {
+ throw new IOException("Invalid character");
+ }
switch (c) {
case '<':
Modified: xmlgraphics/batik/trunk/sources/org/apache/batik/dom/util/SAXDocumentFactory.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/apache/batik/dom/util/SAXDocumentFactory.java?rev=662304&r1=662303&r2=662304&view=diff
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/dom/util/SAXDocumentFactory.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/dom/util/SAXDocumentFactory.java Sun Jun 1 18:37:54 2008
@@ -47,6 +47,7 @@
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
+import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
@@ -106,6 +107,12 @@
* Contains collected string data. May be Text, CDATA or Comment.
*/
protected StringBuffer stringBuffer = new StringBuffer();
+
+ /**
+ * The DTD to use when the document is created.
+ */
+ protected DocumentType doctype;
+
/**
* Indicates if stringBuffer has content, needed in case of
* zero sized "text" content.
@@ -320,6 +327,7 @@
currentNode = null;
Document ret = document;
document = null;
+ doctype = null;
return ret;
}
@@ -440,6 +448,7 @@
currentNode = null;
Document ret = document;
document = null;
+ doctype = null;
locator = null;
parser = null;
return ret;
@@ -531,6 +540,7 @@
inProlog = true;
currentNode = null;
document = null;
+ doctype = null;
isStandalone = false;
xmlVersion = XMLConstants.XML_VERSION_10;
@@ -614,7 +624,7 @@
String nsURI = namespaces.get(nsp);
if (currentNode == null) {
implementation = getDOMImplementation(version);
- document = implementation.createDocument(nsURI, rawName, null);
+ document = implementation.createDocument(nsURI, rawName, doctype);
Iterator i = preInfo.iterator();
currentNode = e = document.getDocumentElement();
while (i.hasNext()) {
@@ -733,6 +743,7 @@
public void startDTD(String name, String publicId, String systemId)
throws SAXException {
appendStringData(); // Add collected string data before entering DTD
+ doctype = implementation.createDocumentType(name, publicId, systemId);
inDTD = true;
}
Modified: xmlgraphics/batik/trunk/sources/org/apache/batik/script/Window.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/apache/batik/script/Window.java?rev=662304&r1=662303&r2=662304&view=diff
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/script/Window.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/script/Window.java Sun Jun 1 18:37:54 2008
@@ -82,6 +82,11 @@
Node parseXML(String text, Document doc);
/**
+ * Serializes the given node.
+ */
+ String printNode(Node n);
+
+ /**
* Gets data from the given URI.
* @param uri The URI where the data is located.
* @param h A handler called when the data is available.
Modified: xmlgraphics/batik/trunk/sources/org/apache/batik/script/rhino/WindowWrapper.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/apache/batik/script/rhino/WindowWrapper.java?rev=662304&r1=662303&r2=662304&view=diff
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/script/rhino/WindowWrapper.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/script/rhino/WindowWrapper.java Sun Jun 1 18:37:54 2008
@@ -30,7 +30,9 @@
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
+
import org.w3c.dom.Document;
+import org.w3c.dom.Node;
/**
* This class wraps a Window object to expose it to the interpreter.
@@ -60,8 +62,8 @@
public WindowWrapper(Context context) {
super(context);
String[] names = { "setInterval", "setTimeout", "clearInterval",
- "clearTimeout", "parseXML", "getURL", "postURL",
- "alert", "confirm", "prompt" };
+ "clearTimeout", "parseXML", "printNode", "getURL",
+ "postURL", "alert", "confirm", "prompt" };
this.defineFunctionProperties(names, WindowWrapper.class,
ScriptableObject.DONTENUM);
}
@@ -187,6 +189,32 @@
}
/**
+ * Wraps the 'printNode' method of the Window interface.
+ */
+ public static Object printNode(Context cx,
+ Scriptable thisObj,
+ final Object[] args,
+ Function funObj) {
+ if (args.length != 1) {
+ throw Context.reportRuntimeError("invalid argument count");
+ }
+
+ WindowWrapper ww = (WindowWrapper)thisObj;
+ final Window window = ww.window;
+
+ AccessControlContext acc =
+ ((RhinoInterpreter)window.getInterpreter()).getAccessControlContext();
+
+ Object ret = AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return window.printNode
+ ((Node) Context.jsToJava(args[0], Node.class));
+ }
+ }, acc);
+ return Context.toString(ret);
+ }
+
+ /**
* Wraps the 'getURL' method of the Window interface.
*/
public static void getURL(Context cx,
@@ -366,7 +394,7 @@
if (result == null) {
return null;
}
- return Context.toObject(result, thisObj);
+ return Context.toString(result);
}
/**