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:
parent
6b7682b5a3
commit
efa4512055
4 changed files with 99 additions and 36 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue