From d6d714135080f346a22441131ae76eb845e4e735 Mon Sep 17 00:00:00 2001 From: hns Date: Wed, 10 Jul 2002 16:56:15 +0000 Subject: [PATCH] First sketch to implement sparse and deep parsing. The old demo app examples still work. The new features may require some more tweaking, possibly also on the mapping prototype file syntax. --- src/helma/objectmodel/dom/XmlConverter.java | 131 ++++++++++++++++---- 1 file changed, 108 insertions(+), 23 deletions(-) diff --git a/src/helma/objectmodel/dom/XmlConverter.java b/src/helma/objectmodel/dom/XmlConverter.java index 05e19c5d..2b4bf53a 100644 --- a/src/helma/objectmodel/dom/XmlConverter.java +++ b/src/helma/objectmodel/dom/XmlConverter.java @@ -69,25 +69,40 @@ public class XmlConverter implements XmlConstants { public INode convert( InputStream in, INode helmaNode ) throws RuntimeException { Document document = XmlUtil.parse (in); if ( document!=null && document.getDocumentElement()!=null ) { - return convert( document.getDocumentElement(), helmaNode ); + return convert( document.getDocumentElement(), helmaNode, new HashMap() ); } else { return helmaNode; } } - public INode convert( Element element, INode helmaNode ) { + public INode convert( Element element, INode helmaNode, Map nodeCache ) { offset++; + // previousNode is used to cache previous nodes with the same prototype + // so we can reset it in the nodeCache after we've run + Object previousNode = null; if (DEBUG) debug("reading " + element.getNodeName() ); helmaNode.setName( element.getNodeName() ); String prototype = props.getProperty(element.getNodeName()+"._prototype"); - if ( prototype == null ) + if ( prototype == null && !sparse ) prototype = "HopObject"; - helmaNode.setPrototype( prototype ); - attributes(element, helmaNode); - if ( element.hasChildNodes() ) { - children(element, helmaNode); + // if we have a prototype (either explicit or implicit "hopobject"), + // set it on the Helma node and store it in the node cache. + if ( prototype != null ) { + helmaNode.setPrototype( prototype ); + previousNode = nodeCache.put (prototype, helmaNode); } + + // check attributes of the current element + attributes(element, helmaNode, nodeCache); + // check child nodes of the current element + if ( element.hasChildNodes() ) + children(element, helmaNode, nodeCache); + + // if it exists, restore the previous node we've replaced in the node cache. + if (previousNode != null) + nodeCache.put (prototype, previousNode); + offset--; return helmaNode; } @@ -95,9 +110,10 @@ public class XmlConverter implements XmlConstants { /** * parse xml children and create hopobject-children */ - private INode children( Element element, helma.objectmodel.INode helmaNode ) { + private INode children( Element element, helma.objectmodel.INode helmaNode, Map nodeCache ) { NodeList list = element.getChildNodes(); int len = list.getLength(); + boolean nodeHasPrototype = helmaNode.getPrototype() != null; StringBuffer textcontent = new StringBuffer(); String domKey, helmaKey; for ( int i=0; i append to StringBuffer - if ( childNode.getNodeType()==org.w3c.dom.Node.TEXT_NODE ) { + if ( childNode.getNodeType() == Node.TEXT_NODE || + childNode.getNodeType() == Node.CDATA_SECTION_NODE ) { textcontent.append( childNode.getNodeValue().trim() ); continue; } - // FIXME: handle CDATA! - // it's some kind of element (property or child) - if ( childNode.getNodeType()==org.w3c.dom.Node.ELEMENT_NODE ) { + if ( childNode.getNodeType() == Node.ELEMENT_NODE ) { Element childElement = (Element)childNode; @@ -129,7 +155,16 @@ public class XmlConverter implements XmlConstants { helmaKey = childElement.getNodeName().replace(':',defaultSeparator); if (DEBUG) debug("childtext-2-property mapping, helmaKey " + helmaKey + " for domKey " + domKey ); - if ( helmaNode.getString(helmaKey,false)==null ) { + // check if helmaKey contains an explicit prototype name in which to + // set the property. + int dot = helmaKey.indexOf("."); + if (dot > -1) { + String prototype = helmaKey.substring (0, dot); + INode node = (INode) nodeCache.get (prototype); + if (node != null) + node.setString (helmaKey.substring (dot+1), XmlUtil.getTextContent (childNode)); + } + if ( helmaNode.getPrototype() != null && helmaNode.getString(helmaKey,false)==null ) { helmaNode.setString( helmaKey, XmlUtil.getTextContent(childNode) ); if (DEBUG) debug("childtext-2-property mapping, setting " + helmaKey + " as string" ); @@ -147,10 +182,23 @@ public class XmlConverter implements XmlConstants { helmaKey = childElement.getNodeName().replace(':',defaultSeparator); if (DEBUG) debug("child-2-property mapping, helmaKey " + helmaKey + " for domKey " + domKey); - if ( helmaNode.getNode(helmaKey,false)==null ) { - convert( childElement, helmaNode.createNode(helmaKey) ); + // get the node on which to opererate, depending on the helmaKey + // value from the properties file. + INode node = helmaNode; + int dot = helmaKey.indexOf("."); + if (dot > -1) { + String prototype = helmaKey.substring (0, dot); + if (!prototype.equalsIgnoreCase (node.getPrototype())) + node = (INode) nodeCache.get (prototype); + helmaKey = helmaKey.substring (dot+1); + } + if (node == null) + continue; + + if ( node.getNode(helmaKey,false)==null ) { + convert( childElement, node.createNode(helmaKey), nodeCache ); if (DEBUG) - debug( "read " + childElement.toString() + helmaNode.getNode(helmaKey,false).toString() ); + debug( "read " + childElement.toString() + node.getNode(helmaKey,false).toString() ); } continue; } @@ -162,15 +210,29 @@ public class XmlConverter implements XmlConstants { // do we need a mapping directly among _children of helmaNode? // can either be through property elname._children=_all or elname._children=childname if( childrenMapping!=null && ( childrenMapping.equals("_all") || childrenMapping.equals(childElement.getNodeName()) ) ) { - newHelmaNode = convert(childElement, helmaNode.createNode(null) ); + newHelmaNode = convert(childElement, helmaNode.createNode(null), nodeCache ); } - // which name to choose for a virtual subnode: + // in which virtual subnode collection should objects of this type be stored? helmaKey = props.getProperty(domKey); - if ( helmaKey==null ) { + if ( helmaKey==null && !sparse ) { helmaKey = childElement.getNodeName().replace(':',defaultSeparator); } + + // get the node on which to opererate, depending on the helmaKey + // value from the properties file. + INode node = helmaNode; + int dot = helmaKey.indexOf("."); + if (dot > -1) { + String prototype = helmaKey.substring (0, dot); + if (!prototype.equalsIgnoreCase (node.getPrototype())) + node = (INode) nodeCache.get (prototype); + helmaKey = helmaKey.substring (dot+1); + } + if (node == null) + continue; + // try to get the virtual node - helma.objectmodel.INode worknode = helmaNode.getNode( helmaKey, false ); + helma.objectmodel.INode worknode = node.getNode( helmaKey, false ); if ( worknode==null ) { // if virtual node doesn't exist, create it worknode = helmaNode.createNode( helmaKey ); @@ -181,7 +243,7 @@ public class XmlConverter implements XmlConstants { if ( newHelmaNode!=null ) { worknode.addNode(newHelmaNode); } else { - convert( childElement, worknode.createNode( null ) ); + convert( childElement, worknode.createNode( null ), nodeCache ); } } // forget about other types (comments etc) @@ -193,6 +255,8 @@ public class XmlConverter implements XmlConstants { helmaKey = props.getProperty(element.getNodeName()+"._text"); if ( helmaKey==null ) helmaKey = "text"; + if (DEBUG) + debug ("setting text "+textcontent+" to property "+helmaKey+" of object "+helmaNode); helmaNode.setString(helmaKey, textcontent.toString().trim() ); } @@ -202,12 +266,14 @@ public class XmlConverter implements XmlConstants { /** * set element's attributes as properties of helmaNode */ - private INode attributes( Element element, INode helmaNode ) { + private INode attributes( Element element, INode helmaNode, Map nodeCache ) { NamedNodeMap nnm = element.getAttributes(); int len = nnm.getLength(); for ( int i=0; i -1) { + String prototype = helmaKey.substring (0, dot); + INode node = (INode) nodeCache.get (prototype); + if (node != null) + node.setString (helmaKey.substring(dot+1), attr.getNodeValue()); + } else if (helmaNode.getPrototype() != null) { + helmaNode.setString( helmaKey, attr.getNodeValue() ); + } } } return helmaNode; @@ -231,6 +315,7 @@ public class XmlConverter implements XmlConstants { sparse = "sparse".equalsIgnoreCase (props.getProperty("_mode")); } + /** for testing */ void debug(Object msg) { for ( int i=0; i