Tentative fix for bug 113: numbers as names of named properties do not

work in embedded db

When a property is encountered that *might* not be suitable as XML element name,
we use "property" as element name and add the real property name as attribute to
that element.
This commit is contained in:
hns 2002-10-30 16:35:48 +00:00
parent 6b7682b5a3
commit efa4512055
4 changed files with 99 additions and 36 deletions

View file

@ -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

View file

@ -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

View file

@ -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());

View file

@ -131,7 +131,7 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
write ("<xmlroot xmlns:hop=\"");
write (NAMESPACE);
writeln ("\">");
write (node,null,0);
write (node, null, null, 0);
writeln ("</xmlroot>");
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. </root>
*/
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. <parent idref="35" prototyperef="hopobject"/>
*/
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<l; i++) {
c = str.charAt (i);
if (!Character.isLetterOrDigit(c) && c != '-' && c != '_')
return false;
}
return true;
}
}