Index: XMLDecoder.java =================================================================== RCS file: /cvsroot/cayenne/cayenne/src/cayenne/java/org/objectstyle/cayenne/xml/XMLDecoder.java,v retrieving revision 1.10 diff -u -r1.10 XMLDecoder.java --- XMLDecoder.java 6 Oct 2005 19:50:12 -0000 1.10 +++ XMLDecoder.java 14 Oct 2005 03:40:39 -0000 ..-65,13 +65,16 @@ import java.util.List; import java.util.Map; -import org.jdom.Document; -import org.jdom.Element; -import org.jdom.input.SAXBuilder; +import javax.xml.parsers.DocumentBuilder; + import org.objectstyle.cayenne.CayenneRuntimeException; import org.objectstyle.cayenne.DataObject; import org.objectstyle.cayenne.access.DataContext; import org.objectstyle.cayenne.property.PropertyUtils; +import org.objectstyle.cayenne.util.Util; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.InputSource; /** * XMLDecoder is used to decode XML into objects. ..-195,7 +198,7 @@ */ public Object decodeObject(String xmlTag) { // Find the XML element corresponding to the supplied tag. - Element child = root.getChild(xmlTag); + Element child = XMLUtil.getChild(root, xmlTag); return decodeObject(child); } ..-212,11 +215,11 @@ return null; } - String type = child.getAttributeValue("type"); - if (null == type) { + String type = child.getAttribute("type"); + if (Util.isEmptyString(type)) { // TODO should we use String by default? Or guess from the property type? throw new CayenneRuntimeException("No type specified for tag '" - + child.getName() + + child.getNodeName() + "'."); } ..-247,13 +250,12 @@ // The final part checks that we have not previously attempted to decode this // collection, // which is necessary to prevent infinite loops . - if ((((null != child.getParentElement()) && (child - .getParentElement() - .getChildren(child.getName()) - .size() > 1)) || ((null != child.getAttributeValue("forceList")) && (child - .getAttributeValue("forceList") - .toUpperCase().equals("YES")))) - && (false == decodedCollections.contains(child))) { + if ((((null != child.getParentNode()) && (XMLUtil.getChildren( + child.getParentNode(), + child.getNodeName()).size() > 1)) || (child + .getAttribute("forceList") + .toUpperCase().equals("YES"))) + && (!decodedCollections.contains(child))) { return decodeCollection(child); } ..-269,20 +271,24 @@ // If we hit here, then we should be encoding "simple" properties, which are // basically // objects that take a single arg String constructor. - Constructor c = objectClass.getConstructor(new Class[] {String.class}); + Constructor c = objectClass.getConstructor(new Class[] { + String.class + }); if (c != null) { // Create a new object of the type supplied as the "type" attribute // in the XML element that // represents the XML element's text value. // E.g., for 13, this is // equivalent to new Integer("13"); - - return c.newInstance(new Object[] {child.getText()}); + + return c.newInstance(new Object[] { + XMLUtil.getText(child) + }); } } catch (Exception e) { throw new CayenneRuntimeException("Error decoding tag '" - + child.getName() + + child.getNodeName() + "'", e); } ..-292,7 +298,7 @@ throw new CayenneRuntimeException( "Error decoding tag '" - + child.getName() + + child.getNodeName() + "': " + "specified class does not have a constructor taking either a String or an XMLDecoder"); } ..-306,7 +312,8 @@ public String decodeString(String xmlTag) { // Find the XML element corresponding to the supplied tag, and simply // return its text. - return root.getChildText(xmlTag); + Element child = XMLUtil.getChild(root, xmlTag); + return child != null ? XMLUtil.getText(child) : null; } /** ..-322,7 +329,7 @@ Document data = parse(xml); // Delegate to the decode() method that works on JDOM elements. - return decodeElement(data.getRootElement()); + return decodeElement(data.getDocumentElement()); } /** ..-342,7 +349,9 @@ // MappingUtils will really do all the work. XMLMappingUtil mu = new XMLMappingUtil(mappingUrl); - Object ret = mu.decode(data.getRootElement()); + + // TODO: + Object ret = null; // mu.decode(data.getDocumentElement()); if (null != dc) { dc.registerNewObject((DataObject) ret); ..-399,10 +408,10 @@ Collection ret; try { - String parentClass = xml.getParentElement().getAttributeValue("type"); + String parentClass = ((Element) xml.getParentNode()).getAttribute("type"); Object property = Class.forName(parentClass).newInstance(); Collection c = (Collection) PropertyUtils.getProperty(property, xml - .getName()); + .getNodeName()); ret = (Collection) c.getClass().newInstance(); } ..-415,8 +424,10 @@ // Each child of the root corresponds to an XML representation of // the object. The idea is decode each of those into an object and add them to the // list to be returned. - for (Iterator it = xml.getParentElement().getChildren(xml.getName()).iterator(); it - .hasNext();) { + Iterator it = XMLUtil + .getChildren(xml.getParentNode(), xml.getNodeName()) + .iterator(); + while (it.hasNext()) { // Decode the object. Element e = (Element) it.next(); decodedCollections.add(e); ..-434,42 +445,43 @@ * *..aram xml The wrapped XML encoding of the list of DataObjects. *..eturn The list of decoded DataObjects. - *..hrows CayenneRuntimeException + *..hrows CayenneRuntimeException */ public static List decodeList(Reader xml) throws CayenneRuntimeException { return decodeList(xml, null, null); } /** - * Decodes a list of DataObjects, registering them the supplied - * DataContext. + * Decodes a list of DataObjects, registering them the supplied DataContext. * *..aram xml The wrapped XML encoding of the list of DataObjects. *..aram dc The DataContext to register the decode DataObjects with. *..eturn The list of decoded DataObjects. - *..hrows CayenneRuntimeException + *..hrows CayenneRuntimeException */ - public static List decodeList(Reader xml, DataContext dc) throws CayenneRuntimeException { + public static List decodeList(Reader xml, DataContext dc) + throws CayenneRuntimeException { return decodeList(xml, null, dc); } - + /** - * Decodes a list of DataObjects using the supplied mapping file to guide - * the decoding process. + * Decodes a list of DataObjects using the supplied mapping file to guide the decoding + * process. * *..aram xml The wrapped XML encoding of the list of DataObjects. *..aram mappingUrl Mapping file describing how the XML elements and object * properties correlate. *..eturn The list of decoded DataObjects. - *..hrows CayenneRuntimeException + *..hrows CayenneRuntimeException */ - public static List decodeList(Reader xml, String mappingUrl) throws CayenneRuntimeException { + public static List decodeList(Reader xml, String mappingUrl) + throws CayenneRuntimeException { return decodeList(xml, mappingUrl, null); } /** - * Decodes a list of DataObjects using the supplied mapping file to guide - * the decoding process, registering them the supplied DataContext. + * Decodes a list of DataObjects using the supplied mapping file to guide the decoding + * process, registering them the supplied DataContext. * *..aram xml The wrapped XML encoding of the list of objects. *..aram mappingUrl Mapping file describing how the XML elements and object ..-481,11 +493,11 @@ public static List decodeList(Reader xml, String mappingUrl, DataContext dc) throws CayenneRuntimeException { XMLDecoder decoder = new XMLDecoder(dc); - Element listRoot = parse(xml).getRootElement(); + Element listRoot = parse(xml).getDocumentElement(); List ret; try { - String parentClass = listRoot.getAttributeValue("type"); + String parentClass = listRoot.getAttribute("type"); ret = (List) Class.forName(parentClass).newInstance(); } catch (Exception ex) { ..-502,7 +514,8 @@ // Each child of the root corresponds to an XML representation of // the object. The idea is decode each of those into an object and add them to the // list to be returned. - for (Iterator it = listRoot.getChildren().iterator(); it.hasNext();) { + Iterator it = XMLUtil.getChildren(listRoot).iterator(); + while (it.hasNext()) { // Decode the object. Element e = (Element) it.next(); decoder.decodedCollections.add(e); ..-513,7 +526,9 @@ o = decoder.decodeElement(e); } else { - o = mu.decode(e); + // TODO: + // o = mu.decode(e); + o = null; } // Register the decoded object with the data context if necessary. ..-532,17 +547,14 @@ * Takes the XML wrapped in a Reader and returns a JDOM Document representation of it. * *..aram in Wrapped XML. - *..eturn JDOM Document wrapping the XML for use throughout the rest of the decoder. + *..eturn DOM Document wrapping the XML for use throughout the rest of the decoder. *..hrows CayenneRuntimeException */ private static Document parse(Reader in) throws CayenneRuntimeException { - // Read in the XML file holding the data to be constructed into an - // object. - SAXBuilder parser = new SAXBuilder(); - try { - return parser.build(in); + DocumentBuilder builder = XMLUtil.newBuilder(); + return builder.parse(new InputSource(in)); } catch (Exception ex) { throw new CayenneRuntimeException("Error parsing XML", ex); Index: XMLUtil.java =================================================================== RCS file: XMLUtil.java diff -N XMLUtil.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ XMLUtil.java 1 Jan 1970 00:00:00 -0000 ..-0,0 +1,122 @@ +package org.objectstyle.cayenne.xml; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.commons.collections.Predicate; +import org.w3c.dom.CharacterData; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + *..ince 1.2 + *..uthor Andrus Adamchik + */ +class XMLUtil { + + static DocumentBuilderFactory sharedFactory; + + static DocumentBuilder newBuilder() throws ParserConfigurationException { + if (sharedFactory == null) { + sharedFactory = DocumentBuilderFactory.newInstance(); + } + + return sharedFactory.newDocumentBuilder(); + } + + static String getText(Node node) { + + NodeList nodes = node.getChildNodes(); + int len = nodes.getLength(); + + if (len == 0) { + return null; + } + + StringBuffer text = new StringBuffer(); + for (int i = 0; i < len; i++) { + Node child = nodes.item(i); + + if(child instanceof CharacterData) { + text.append(((CharacterData) child).getData()); + } + } + + return text.length() == 0 ? null : text.toString(); + } + + static Element getChild(Node node, final String name) { + Predicate p = new Predicate() { + + public boolean evaluate(Object object) { + if (object instanceof Element) { + Element e = (Element) object; + return name.equals(e.getNodeName()); + } + + return false; + } + }; + + return (Element) firstMatch(node.getChildNodes(), p); + } + + static List getChildren(Node node, final String name) { + Predicate p = new Predicate() { + + public boolean evaluate(Object object) { + if (object instanceof Element) { + Element e = (Element) object; + return name.equals(e.getNodeName()); + } + + return false; + } + }; + + return allMatches(node.getChildNodes(), p); + } + + static List getChildren(Node node) { + Predicate p = new Predicate() { + + public boolean evaluate(Object object) { + return object instanceof Element; + } + }; + + return allMatches(node.getChildNodes(), p); + } + + private static Node firstMatch(NodeList list, Predicate predicate) { + int len = list.getLength(); + + for (int i = 0; i < len; i++) { + Node node = list.item(i); + if (predicate.evaluate(node)) { + return node; + } + } + + return null; + } + + private static List allMatches(NodeList list, Predicate predicate) { + int len = list.getLength(); + List children = new ArrayList(len); + + for (int i = 0; i < len; i++) { + Node node = list.item(i); + if (predicate.evaluate(node)) { + children.add(node); + } + } + + return children; + } +}