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
		Add a link
		
	
		Reference in a new issue