diff --git a/src/helma/objectmodel/dom/XmlDatabaseReader.java b/src/helma/objectmodel/dom/XmlDatabaseReader.java
index 0222ec75..73db07c2 100644
--- a/src/helma/objectmodel/dom/XmlDatabaseReader.java
+++ b/src/helma/objectmodel/dom/XmlDatabaseReader.java
@@ -99,20 +99,29 @@ public final class XmlDatabaseReader extends DefaultHandler implements XmlConsta
} else if ("hop:parent".equals (qName)) {
currentNode.setParentHandle (handle);
} else {
- Property prop = new Property (qName, currentNode);
+ // property name may be encoded as "propertyname" attribute,
+ // otherwise it is the element name
+ String propName = atts.getValue ("propertyname");
+ if (propName == null)
+ propName = qName;
+ Property prop = new Property (propName, currentNode);
prop.setNodeHandle (handle);
if (propMap == null) {
propMap = new Hashtable ();
currentNode.setPropMap (propMap);
}
- propMap.put (qName.toLowerCase(), prop);
+ propMap.put (propName.toLowerCase(), prop);
}
} else {
// a primitive property
elementType = atts.getValue ("type");
if (elementType == null)
elementType = "string";
- elementName = qName;
+ // property name may be encoded as "propertyname" attribute,
+ // otherwise it is the element name
+ elementName = atts.getValue ("propertyname");
+ if (elementName == null)
+ elementName = qName;
if (charBuffer == null)
charBuffer = new StringBuffer();
else
diff --git a/src/helma/objectmodel/dom/XmlReader.java b/src/helma/objectmodel/dom/XmlReader.java
index ba3b7ccc..dd52123e 100644
--- a/src/helma/objectmodel/dom/XmlReader.java
+++ b/src/helma/objectmodel/dom/XmlReader.java
@@ -108,11 +108,15 @@ public final class XmlReader extends DefaultHandler implements XmlConstants {
} else {
// it's a named node property
nodeStack.push (currentNode);
- currentNode = currentNode.createNode (qName);
+ // property name may be encoded as "propertyname" attribute,
+ // otherwise it is the element name
+ String propName = atts.getValue ("propertyname");
+ if (propName == null)
+ propName = qName;
+ currentNode = currentNode.createNode (propName);
}
// set the prototype on the current node and
// add it to the map of parsed nodes.
- String name = atts.getValue ("name");
String prototype = atts.getValue ("prototype");
if ( !"".equals(prototype) && !"hopobject".equals(prototype) )
currentNode.setPrototype (prototype);
@@ -120,7 +124,7 @@ public final class XmlReader extends DefaultHandler implements XmlConstants {
convertedNodes.put( key, currentNode );
return;
}
-
+
// check if we have a currentNode to set properties on,
// otherwise throw exception.
if (currentNode == null)
@@ -144,11 +148,16 @@ public final class XmlReader extends DefaultHandler implements XmlConstants {
INode n = (INode) convertedNodes.get (key);
if (n != null) {
if ("hop:child".equals (qName)) {
- // add an already parsed node as child to current node
- currentNode.addNode (n);
+ // add an already parsed node as child to current node
+ currentNode.addNode (n);
} else {
- // set an already parsed node as node property to current node
- currentNode.setNode (qName, n);
+ // set an already parsed node as node property to current node
+ // property name may be encoded as "propertyname" attribute,
+ // otherwise it is the element name
+ String propName = atts.getValue ("propertyname");
+ if (propName == null)
+ propName = qName;
+ currentNode.setNode (propName, n);
}
}
} else {
@@ -158,7 +167,11 @@ public final class XmlReader extends DefaultHandler implements XmlConstants {
elementType = atts.getValue ("type");
if (elementType == null)
elementType = "string";
- elementName = qName;
+ // property name may be encoded as "propertyname" attribute,
+ // otherwise it is the element name
+ elementName = atts.getValue ("propertyname");
+ if (elementName == null)
+ elementName = qName;
if (charBuffer == null)
charBuffer = new StringBuffer();
else
diff --git a/src/helma/objectmodel/dom/XmlUtil.java b/src/helma/objectmodel/dom/XmlUtil.java
index e4c519ea..d2eaecf9 100644
--- a/src/helma/objectmodel/dom/XmlUtil.java
+++ b/src/helma/objectmodel/dom/XmlUtil.java
@@ -30,6 +30,7 @@ public class XmlUtil {
return domBuilder;
} else {
try {
+ // domBuilderFactory.setExpandEntityReferences (false);
domBuilder = domBuilderFactory.newDocumentBuilder();
domBuilders.put (Thread.currentThread(), domBuilder);
return domBuilder;
@@ -48,7 +49,7 @@ public class XmlUtil {
DocumentBuilder d = getDocumentBuilder();
try {
Document doc = d.parse (in);
- doc.normalize();
+ // doc.normalize();
return doc;
} catch (SAXException e) {
throw new RuntimeException ("Bad xml-code: "+e.toString());
diff --git a/src/helma/objectmodel/dom/XmlWriter.java b/src/helma/objectmodel/dom/XmlWriter.java
index 20675320..bcf76357 100644
--- a/src/helma/objectmodel/dom/XmlWriter.java
+++ b/src/helma/objectmodel/dom/XmlWriter.java
@@ -131,7 +131,7 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
write ("");
- write (node,null,0);
+ write (node, null, null, 0);
writeln ("");
convertedNodes = null;
return true;
@@ -142,7 +142,7 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
* references are made here if a node already has been fully printed
* or if this is the last level that's going to be dumped
*/
- public void write (INode node, String name, int level) throws IOException {
+ public void write (INode node, String elementName, String propName, int level) throws IOException {
if (node==null)
return;
// if (stopTypes != null && stopTypes.contains (node.getPrototype()))
@@ -150,21 +150,22 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
int previousLength = prefix.length();
prefix.append(indent);
if ( ++level>maxLevels ) {
- writeReferenceTag (node, name);
+ writeReferenceTag (node, elementName, propName);
prefix.setLength( previousLength );
return;
}
if ( convertedNodes.contains(node) ) {
- writeReferenceTag (node, name);
+ writeReferenceTag (node, elementName, propName);
} else {
convertedNodes.addElement (node);
- writeTagOpen (node,name);
- if ( node.getParent()!=null ) {
- writeReferenceTag (node.getParent(),"hop:parent");
+ writeTagOpen (node, elementName, propName);
+ INode parent = node.getParent ();
+ if ( parent!=null ) {
+ writeReferenceTag (parent, "hop:parent", null);
}
- writeProperties (node,level);
- writeChildren (node,level);
- writeTagClose (node,name);
+ writeProperties (node, level);
+ writeChildren (node, level);
+ writeTagClose (elementName);
}
prefix.setLength( previousLength );
}
@@ -191,39 +192,52 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
String key = (String)e.nextElement();
IProperty prop = node.get(key,false);
if ( prop!=null ) {
+ boolean validName = isValidElementName (key);
+ String elementName, propName;
+ if (validName) {
+ elementName = key;
+ propName = null;
+ } else {
+ elementName = "property";
+ propName = key;
+ }
int type = prop.getType();
if( type==IProperty.NODE ) {
- write (node.getNode(key,false), key, level);
+ write (prop.getNodeValue(), elementName, propName, level);
} else {
- writeProperty (node.get(key,false));
+ writeProperty (prop, elementName, propName);
}
}
}
}
- public void writeNullProperty (String key) throws IOException {
+ /* public void writeNullProperty (String key) throws IOException {
write (prefix.toString());
write (indent);
write ("<");
write (key);
write (" type=\"null\"/>");
write (LINESEPARATOR);
- }
+ } */
/**
* write a single property, set attribute type according to type,
* apply xml-encoding.
*/
- public void writeProperty (IProperty property) throws IOException {
+ public void writeProperty (IProperty property, String elementName, String propName) throws IOException {
int propType = property.getType();
// we can't encode java objects in XML
if (propType == IProperty.JAVAOBJECT)
return;
- String propName = property.getName();
write (prefix.toString());
write (indent);
write ("<");
- write (propName);
+ write (elementName);
+ if (propName != null) {
+ write (" propertyname=\"");
+ write (HtmlEncoder.encodeXml (propName));
+ write ("\"");
+ }
switch (propType) {
case IProperty.BOOLEAN:
write (" type=\"boolean\">");
@@ -248,7 +262,7 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
write ( str );
}
write ("");
- write (propName);
+ write (elementName);
write (">");
write (LINESEPARATOR);
}
@@ -266,7 +280,7 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
Enumeration e = node.getSubnodes();
while (e.hasMoreElements()) {
INode nextNode = (INode)e.nextElement();
- write (nextNode, "hop:child", level);
+ write (nextNode, "hop:child", null, level);
}
}
@@ -274,12 +288,16 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
* write an opening tag for a node. Include id and prototype, use a
* name if parameter is non-empty.
*/
- public void writeTagOpen (INode node, String name) throws IOException {
+ public void writeTagOpen (INode node, String name, String propName) throws IOException {
write (prefix.toString());
write ("<");
write ( (name==null)?"hopobject" : name);
write (" id=\"");
write (getNodeIdentifier(node));
+ if (propName != null) {
+ write ("\" propertyname=\"");
+ write (HtmlEncoder.encodeXml (propName));
+ }
write ("\" name=\"");
write (node.getName());
write ("\" prototype=\"");
@@ -297,7 +315,7 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
* write a closing tag for a node
* e.g.
*/
- public void writeTagClose (INode node, String name) throws IOException {
+ public void writeTagClose (String name) throws IOException {
write (prefix.toString());
write ("");
write ( (name==null)?"hopobject" : name);
@@ -310,16 +328,19 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
* been written out before.
* e.g.
*/
- public void writeReferenceTag (INode node, String name) throws IOException {
+ public void writeReferenceTag (INode node, String name, String propName) throws IOException {
write (prefix.toString());
write ("<");
write ( (name==null)?"hopobject" : name);
write ( " idref=\"");
write (getNodeIdentifier(node));
+ if (propName != null) {
+ write ("\" propertyname=\"");
+ write (HtmlEncoder.encodeXml (propName));
+ }
write ("\" prototyperef=\"");
write (getNodePrototype(node));
- write ("\"");
- write ("/>");
+ write ("\"/>");
write (LINESEPARATOR);
}
@@ -352,5 +373,24 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
write (LINESEPARATOR);
}
+
+ /**
+ * Check if a string is usable as XML element name. If not, the name
+ * will be appended as attribute to the XML element. We are
+ * conservative here, preferring to return false rather too often than
+ * not enough.
+ */
+ private boolean isValidElementName (String str) {
+ char c = str.charAt (0);
+ if (!Character.isLetter(c))
+ return false;
+ int l = str.length();
+ for (int i=1; i