From 3fa6bf9bdc860459907224f1cd0dc4701a8ffcf7 Mon Sep 17 00:00:00 2001 From: Felipe Barriga Richards Date: Mon, 6 Feb 2017 15:49:45 -0300 Subject: [PATCH] axmlrpc: Use XmlPullParser to deserialize xml objects. Serialization remains the same. Code copied from WordPress-Android. https://github.com/wordpress-mobile/WordPress-Android --- .../de/timroes/axmlrpc/ResponseParser.java | 92 ++++----- .../axmlrpc/serializer/ArraySerializer.java | 33 --- .../axmlrpc/serializer/Base64Serializer.java | 4 - .../axmlrpc/serializer/BooleanSerializer.java | 5 - .../serializer/DateTimeSerializer.java | 12 +- .../axmlrpc/serializer/DoubleSerializer.java | 4 - .../axmlrpc/serializer/IntSerializer.java | 4 - .../axmlrpc/serializer/LongSerializer.java | 4 - .../axmlrpc/serializer/NullSerializer.java | 4 - .../axmlrpc/serializer/Serializer.java | 9 - .../axmlrpc/serializer/SerializerHandler.java | 191 ++++++++++++------ .../axmlrpc/serializer/StringSerializer.java | 11 +- .../axmlrpc/serializer/StructSerializer.java | 59 ------ 13 files changed, 165 insertions(+), 267 deletions(-) diff --git a/app/src/main/java/de/timroes/axmlrpc/ResponseParser.java b/app/src/main/java/de/timroes/axmlrpc/ResponseParser.java index b0968963..b6d110f1 100644 --- a/app/src/main/java/de/timroes/axmlrpc/ResponseParser.java +++ b/app/src/main/java/de/timroes/axmlrpc/ResponseParser.java @@ -3,10 +3,10 @@ package de.timroes.axmlrpc; import de.timroes.axmlrpc.serializer.SerializerHandler; import java.io.InputStream; import java.util.Map; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import org.w3c.dom.Document; -import org.w3c.dom.Element; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlPullParserFactory; /** * The ResponseParser parses the response of an XMLRPC server to an object. @@ -28,69 +28,45 @@ class ResponseParser { * @throws XMLRPCServerException Will be thrown, if the server returns an error. */ public Object parse(InputStream response) throws XMLRPCException { - try { - - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - DocumentBuilder builder = factory.newDocumentBuilder(); - Document dom = builder.parse(response); - Element e = dom.getDocumentElement(); - - // Check for root tag - if(!e.getNodeName().equals(XMLRPCClient.METHOD_RESPONSE)) { - throw new XMLRPCException("MethodResponse root tag is missing."); - } - - e = XMLUtil.getOnlyChildElement(e.getChildNodes()); - - if(e.getNodeName().equals(XMLRPCClient.PARAMS)) { - - e = XMLUtil.getOnlyChildElement(e.getChildNodes()); - - if(!e.getNodeName().equals(XMLRPCClient.PARAM)) { - throw new XMLRPCException("The params tag must contain a param tag."); + XmlPullParser pullParser = XmlPullParserFactory.newInstance().newPullParser(); + pullParser.setInput(response, "UTF-8"); + + pullParser.nextTag(); + pullParser.require(XmlPullParser.START_TAG, null, XMLRPCClient.METHOD_RESPONSE); + + pullParser.nextTag(); // either TAG_PARAMS () or TAG_FAULT () + String tag = pullParser.getName(); + if (tag.equals(XMLRPCClient.PARAMS)) { + // normal response + pullParser.nextTag(); // TAG_PARAM () + pullParser.require(XmlPullParser.START_TAG, null, XMLRPCClient.PARAM); + pullParser.nextTag(); // TAG_VALUE () + // no parser.require() here since its called in XMLRPCSerializer.deserialize() below + // deserialize result + Object obj = SerializerHandler.getDefault().deserialize(pullParser); + return obj; + } else if (tag.equals(XMLRPCClient.FAULT)) { + // fault response + pullParser.nextTag(); // TAG_VALUE () + Map map = (Map) SerializerHandler.getDefault().deserialize(pullParser); + + //Check that required tags are in the response + if (!map.containsKey(FAULT_STRING) || !map.containsKey(FAULT_CODE)) { + throw new XMLRPCException("Bad XMLRPC Fault response received - and/or missing!"); } - - return getReturnValueFromElement(e); - - } else if(e.getNodeName().equals(XMLRPCClient.FAULT)) { - - @SuppressWarnings("unchecked") - Map o = (Map)getReturnValueFromElement(e); - - throw new XMLRPCServerException((String)o.get(FAULT_STRING), (Integer)o.get(FAULT_CODE)); - + throw new XMLRPCServerException((String) map.get(FAULT_STRING), (Integer) map.get(FAULT_CODE)); + } else { + throw new XMLRPCException("Bad tag <" + tag + "> in XMLRPC response - neither nor "); } - throw new XMLRPCException("The methodResponse tag must contain a fault or params tag."); - + } catch (XmlPullParserException ex) { + throw new XMLRPCException("Error parsing response.", ex); } catch (Exception ex) { - if(ex instanceof XMLRPCServerException) throw (XMLRPCServerException)ex; else throw new XMLRPCException("Error getting result from server.", ex); - } - } - - /** - * This method takes an element (must be a param or fault element) and - * returns the deserialized object of this param tag. - * - * @param element An param element. - * @return The deserialized object within the given param element. - * @throws XMLRPCException Will be thrown when the structure of the document - * doesn't match the XML-RPC specification. - */ - private Object getReturnValueFromElement(Element element) throws XMLRPCException { - - element = XMLUtil.getOnlyChildElement(element.getChildNodes()); - - return SerializerHandler.getDefault().deserialize(element); - - } - } \ No newline at end of file diff --git a/app/src/main/java/de/timroes/axmlrpc/serializer/ArraySerializer.java b/app/src/main/java/de/timroes/axmlrpc/serializer/ArraySerializer.java index 5850f806..3e48151c 100644 --- a/app/src/main/java/de/timroes/axmlrpc/serializer/ArraySerializer.java +++ b/app/src/main/java/de/timroes/axmlrpc/serializer/ArraySerializer.java @@ -18,39 +18,6 @@ public class ArraySerializer implements Serializer { private static final String ARRAY_DATA = "data"; private static final String ARRAY_VALUE = "value"; - public Object deserialize(Element content) throws XMLRPCException { - - List list = new ArrayList(); - - Element data = XMLUtil.getOnlyChildElement(content.getChildNodes()); - - if(!ARRAY_DATA.equals(data.getNodeName())) { - throw new XMLRPCException("The array must contain one data tag."); - } - - // Deserialize every array element - Node value; - for(int i = 0; i < data.getChildNodes().getLength(); i++) { - - value = data.getChildNodes().item(i); - - // Strip only whitespace text elements and comments - if(value == null || (value.getNodeType() == Node.TEXT_NODE - && value.getNodeValue().trim().length() <= 0) - || value.getNodeType() == Node.COMMENT_NODE) - continue; - - if(value.getNodeType() != Node.ELEMENT_NODE) { - throw new XMLRPCException("Wrong element inside of array."); - } - - list.add(SerializerHandler.getDefault().deserialize((Element)value)); - - } - - return list.toArray(); - } - public XmlElement serialize(Object object) { Iterable iter = (Iterable)object; diff --git a/app/src/main/java/de/timroes/axmlrpc/serializer/Base64Serializer.java b/app/src/main/java/de/timroes/axmlrpc/serializer/Base64Serializer.java index d8e468e9..bffa40bb 100644 --- a/app/src/main/java/de/timroes/axmlrpc/serializer/Base64Serializer.java +++ b/app/src/main/java/de/timroes/axmlrpc/serializer/Base64Serializer.java @@ -12,10 +12,6 @@ import org.w3c.dom.Element; */ public class Base64Serializer implements Serializer { - public Object deserialize(Element content) throws XMLRPCException { - return Base64.decode(XMLUtil.getOnlyTextContent(content.getChildNodes())); - } - public XmlElement serialize(Object object) { return XMLUtil.makeXmlTag(SerializerHandler.TYPE_BASE64, Base64.encode((Byte[])object)); diff --git a/app/src/main/java/de/timroes/axmlrpc/serializer/BooleanSerializer.java b/app/src/main/java/de/timroes/axmlrpc/serializer/BooleanSerializer.java index 4267b092..74bf0fbe 100644 --- a/app/src/main/java/de/timroes/axmlrpc/serializer/BooleanSerializer.java +++ b/app/src/main/java/de/timroes/axmlrpc/serializer/BooleanSerializer.java @@ -11,11 +11,6 @@ import org.w3c.dom.Element; */ public class BooleanSerializer implements Serializer { - public Object deserialize(Element content) throws XMLRPCException { - return (XMLUtil.getOnlyTextContent(content.getChildNodes()).equals("1")) - ? Boolean.TRUE : Boolean.FALSE; - } - public XmlElement serialize(Object object) { return XMLUtil.makeXmlTag(SerializerHandler.TYPE_BOOLEAN, ((Boolean)object == true) ? "1" : "0"); diff --git a/app/src/main/java/de/timroes/axmlrpc/serializer/DateTimeSerializer.java b/app/src/main/java/de/timroes/axmlrpc/serializer/DateTimeSerializer.java index a95219a5..b55e4875 100644 --- a/app/src/main/java/de/timroes/axmlrpc/serializer/DateTimeSerializer.java +++ b/app/src/main/java/de/timroes/axmlrpc/serializer/DateTimeSerializer.java @@ -13,16 +13,8 @@ import org.w3c.dom.Element; */ public class DateTimeSerializer implements Serializer { - private static final String DATETIME_FORMAT = "yyyyMMdd'T'HH:mm:ss"; - private static final SimpleDateFormat DATE_FORMATER = new SimpleDateFormat(DATETIME_FORMAT); - - public Object deserialize(Element content) throws XMLRPCException { - try { - return DATE_FORMATER.parse(XMLUtil.getOnlyTextContent(content.getChildNodes())); - } catch (ParseException ex) { - throw new XMLRPCException("Unable to parse given date.", ex); - } - } + public static final String DATETIME_FORMAT = "yyyyMMdd'T'HH:mm:ss"; + public static final SimpleDateFormat DATE_FORMATER = new SimpleDateFormat(DATETIME_FORMAT); public XmlElement serialize(Object object) { return XMLUtil.makeXmlTag(SerializerHandler.TYPE_DATETIME, diff --git a/app/src/main/java/de/timroes/axmlrpc/serializer/DoubleSerializer.java b/app/src/main/java/de/timroes/axmlrpc/serializer/DoubleSerializer.java index 361ca2d1..3f0b7941 100644 --- a/app/src/main/java/de/timroes/axmlrpc/serializer/DoubleSerializer.java +++ b/app/src/main/java/de/timroes/axmlrpc/serializer/DoubleSerializer.java @@ -13,10 +13,6 @@ import org.w3c.dom.Element; */ public class DoubleSerializer implements Serializer { - public Object deserialize(Element content) throws XMLRPCException { - return Double.valueOf(XMLUtil.getOnlyTextContent(content.getChildNodes())); - } - public XmlElement serialize(Object object) { // Turn double value of object into a BigDecimal to get the // right decimal point format. diff --git a/app/src/main/java/de/timroes/axmlrpc/serializer/IntSerializer.java b/app/src/main/java/de/timroes/axmlrpc/serializer/IntSerializer.java index 5d7b23db..f8f48d7e 100644 --- a/app/src/main/java/de/timroes/axmlrpc/serializer/IntSerializer.java +++ b/app/src/main/java/de/timroes/axmlrpc/serializer/IntSerializer.java @@ -11,10 +11,6 @@ import org.w3c.dom.Element; */ public class IntSerializer implements Serializer { - public Object deserialize(Element content) throws XMLRPCException { - return Integer.parseInt(XMLUtil.getOnlyTextContent(content.getChildNodes())); - } - public XmlElement serialize(Object object) { return XMLUtil.makeXmlTag(SerializerHandler.TYPE_INT, object.toString()); diff --git a/app/src/main/java/de/timroes/axmlrpc/serializer/LongSerializer.java b/app/src/main/java/de/timroes/axmlrpc/serializer/LongSerializer.java index 15ba9f65..1952fb2e 100644 --- a/app/src/main/java/de/timroes/axmlrpc/serializer/LongSerializer.java +++ b/app/src/main/java/de/timroes/axmlrpc/serializer/LongSerializer.java @@ -11,10 +11,6 @@ import org.w3c.dom.Element; */ class LongSerializer implements Serializer { - public Object deserialize(Element content) throws XMLRPCException { - return Long.parseLong(XMLUtil.getOnlyTextContent(content.getChildNodes())); - } - public XmlElement serialize(Object object) { return XMLUtil.makeXmlTag(SerializerHandler.TYPE_LONG, ((Long)object).toString()); diff --git a/app/src/main/java/de/timroes/axmlrpc/serializer/NullSerializer.java b/app/src/main/java/de/timroes/axmlrpc/serializer/NullSerializer.java index e1619b61..ae3424eb 100644 --- a/app/src/main/java/de/timroes/axmlrpc/serializer/NullSerializer.java +++ b/app/src/main/java/de/timroes/axmlrpc/serializer/NullSerializer.java @@ -10,10 +10,6 @@ import org.w3c.dom.Element; */ public class NullSerializer implements Serializer { - public Object deserialize(Element content) throws XMLRPCException { - return null; - } - public XmlElement serialize(Object object) { return new XmlElement(SerializerHandler.TYPE_NULL); } diff --git a/app/src/main/java/de/timroes/axmlrpc/serializer/Serializer.java b/app/src/main/java/de/timroes/axmlrpc/serializer/Serializer.java index c139ebce..5a64c423 100644 --- a/app/src/main/java/de/timroes/axmlrpc/serializer/Serializer.java +++ b/app/src/main/java/de/timroes/axmlrpc/serializer/Serializer.java @@ -12,15 +12,6 @@ import org.w3c.dom.Element; */ public interface Serializer { - /** - * This method takes an xml type element and deserialize it to an object. - * - * @param content Must be an xml element of a specific type. - * @return The deserialized content. - * @throws XMLRPCException Will be thrown whenervt the deserialization fails. - */ - public Object deserialize(Element content) throws XMLRPCException; - /** * This method takes an object and returns a representation as a string * containing the right xml type tag. The returning string must be useable diff --git a/app/src/main/java/de/timroes/axmlrpc/serializer/SerializerHandler.java b/app/src/main/java/de/timroes/axmlrpc/serializer/SerializerHandler.java index 02f25d40..ab81c476 100644 --- a/app/src/main/java/de/timroes/axmlrpc/serializer/SerializerHandler.java +++ b/app/src/main/java/de/timroes/axmlrpc/serializer/SerializerHandler.java @@ -5,11 +5,27 @@ import de.timroes.axmlrpc.XMLRPCException; import de.timroes.axmlrpc.XMLRPCRuntimeException; import de.timroes.axmlrpc.XMLUtil; import de.timroes.axmlrpc.xmlcreator.XmlElement; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; import java.math.BigDecimal; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Calendar; import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; import java.util.Map; -import org.w3c.dom.Element; +import java.util.SimpleTimeZone; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import android.util.Base64; +import android.util.Log; /** * The serializer handler serializes and deserialized objects. @@ -21,6 +37,18 @@ import org.w3c.dom.Element; * @author Tim Roes */ public class SerializerHandler { + private static final String LOG_NAME = "SerializerHandler"; + + public static final String TAG_NAME = "name"; + public static final String TAG_MEMBER = "member"; + public static final String TAG_VALUE = "value"; + public static final String TAG_DATA = "data"; + + + public static final String TYPE_DATE_TIME_ISO8601 = "dateTime.iso8601"; + + static SimpleDateFormat dateFormat = DateTimeSerializer.DATE_FORMATER; + static Calendar cal = Calendar.getInstance(new SimpleTimeZone(0, "GMT")); public static final String TYPE_STRING = "string"; public static final String TYPE_BOOLEAN = "boolean"; @@ -81,83 +109,120 @@ public class SerializerHandler { */ private SerializerHandler(int flags) { this.flags = flags; - string = new StringSerializer( - (flags & XMLRPCClient.FLAGS_NO_STRING_ENCODE) == 0, - (flags & XMLRPCClient.FLAGS_NO_STRING_DECODE) == 0 - ); + string = new StringSerializer((flags & XMLRPCClient.FLAGS_NO_STRING_ENCODE) == 0); } /** - * Deserializes an incoming xml element to an java object. - * The xml element must be the value element around the type element. + * Deserialize an incoming xml to a java object. * The type of the returning object depends on the type tag. * - * @param element An type element from within a value tag. + * @param parser Initialized parser. * @return The deserialized object. - * @throws XMLRPCException Will be thrown whenever an error occurs. + * @throws XmlPullParserException + * @throws IOException + * @throws NumberFormatException */ - public Object deserialize(Element element) throws XMLRPCException { + public static Object deserialize(XmlPullParser parser) throws XmlPullParserException, IOException, NumberFormatException { + parser.require(XmlPullParser.START_TAG, null, TAG_VALUE); - if(!XMLRPCClient.VALUE.equals(element.getNodeName())) { - throw new XMLRPCException("Value tag is missing around value."); - } - - if(!XMLUtil.hasChildElement(element.getChildNodes())) { - // Value element doesn't contain a child element - if((flags & XMLRPCClient.FLAGS_DEFAULT_TYPE_STRING) != 0) { - return string.deserialize(element); - } else { - throw new XMLRPCException("Missing type element inside of value element."); - } - } - - // Grep type element from inside value element - element = XMLUtil.getOnlyChildElement(element.getChildNodes()); - - Serializer s = null; + parser.nextTag(); + String typeNodeName = parser.getName(); - String type; - - // If FLAGS_IGNORE_NAMESPACE has been set, only use local name. - if((flags & XMLRPCClient.FLAGS_IGNORE_NAMESPACES) != 0) { - type = element.getLocalName() == null ? element.getNodeName() : element.getLocalName(); - } else { - type = element.getNodeName(); - } + Object obj; + if (typeNodeName.equals(TYPE_INT) || typeNodeName.equals(TYPE_INT2)) { + String value = parser.nextText(); + try { + obj = Integer.parseInt(value); + } catch (NumberFormatException nfe) { + Log.w(LOG_NAME, "Server replied with an invalid 4 bytes int value, trying to parse it as 8 bytes long."); + obj = Long.parseLong(value); + } + } else + if (typeNodeName.equals(TYPE_LONG)) { + String value = parser.nextText(); + obj = Long.parseLong(value); + } else + if (typeNodeName.equals(TYPE_DOUBLE)) { + String value = parser.nextText(); + obj = Double.parseDouble(value); + } else + if (typeNodeName.equals(TYPE_BOOLEAN)) { + String value = parser.nextText(); + obj = value.equals("1") ? Boolean.TRUE : Boolean.FALSE; + } else + if (typeNodeName.equals(TYPE_STRING)) { + obj = parser.nextText(); + } else + if (typeNodeName.equals(TYPE_DATE_TIME_ISO8601)) { + dateFormat.setCalendar(cal); + String value = parser.nextText(); + try { + obj = dateFormat.parseObject(value); + } catch (ParseException e) { + Log.e(LOG_NAME, "Error parsing date, using non-parsed string."); + obj = value; + } + } else + if (typeNodeName.equals(TYPE_BASE64)) { + String value = parser.nextText(); + BufferedReader reader = new BufferedReader(new StringReader(value)); + String line; + StringBuffer sb = new StringBuffer(); + while ((line = reader.readLine()) != null) { + sb.append(line); + } + obj = Base64.decode(sb.toString(), Base64.DEFAULT); + } else + if (typeNodeName.equals(TYPE_ARRAY)) { + parser.nextTag(); // TAG_DATA () + parser.require(XmlPullParser.START_TAG, null, TAG_DATA); - if((flags & XMLRPCClient.FLAGS_NIL) != 0 && TYPE_NULL.equals(type)) { - s = nil; - } else if(TYPE_STRING.equals(type)) { - s = string; - } else if(TYPE_BOOLEAN.equals(type)) { - s = bool; - } else if(TYPE_DOUBLE.equals(type)) { - s = floating; - } else if (TYPE_INT.equals(type) || TYPE_INT2.equals(type)) { - s = integer; - } else if(TYPE_DATETIME.equals(type)) { - s = datetime; - } else if (TYPE_LONG.equals(type)) { - if((flags & XMLRPCClient.FLAGS_8BYTE_INT) != 0) { - s = long8; - } else { - throw new XMLRPCException("8 byte integer is not in the specification. " - + "You must use FLAGS_8BYTE_INT to enable the i8 tag."); + parser.nextTag(); + List list = new ArrayList(); + while (parser.getName().equals(TAG_VALUE)) { + list.add(deserialize(parser)); + parser.nextTag(); } - } else if(TYPE_STRUCT.equals(type)) { - s = struct; - } else if(TYPE_ARRAY.equals(type)) { - s = array; - } else if(TYPE_BASE64.equals(type)) { - s = base64; + parser.require(XmlPullParser.END_TAG, null, TAG_DATA); + parser.nextTag(); // TAG_ARRAY () + parser.require(XmlPullParser.END_TAG, null, TYPE_ARRAY); + obj = list.toArray(); + } else + if (typeNodeName.equals(TYPE_STRUCT)) { + parser.nextTag(); + Map map = new HashMap(); + while (parser.getName().equals(TAG_MEMBER)) { + String memberName = null; + Object memberValue = null; + while (true) { + parser.nextTag(); + String name = parser.getName(); + if (name.equals(TAG_NAME)) { + memberName = parser.nextText(); + } else + if (name.equals(TAG_VALUE)) { + memberValue = deserialize(parser); + } else { + break; + } + } + if (memberName != null && memberValue != null) { + map.put(memberName, memberValue); + } + parser.require(XmlPullParser.END_TAG, null, TAG_MEMBER); + parser.nextTag(); + } + parser.require(XmlPullParser.END_TAG, null, TYPE_STRUCT); + obj = map; } else { - throw new XMLRPCException("No deserializer found for type '" + type + "'."); + throw new IOException("Cannot deserialize " + parser.getName()); } - - return s.deserialize(element); - + parser.nextTag(); // TAG_VALUE () + parser.require(XmlPullParser.END_TAG, null, TAG_VALUE); + return obj; } + /** * Serialize an object to its representation as an xml element. * The xml element will be the type element for the use within a value tag. diff --git a/app/src/main/java/de/timroes/axmlrpc/serializer/StringSerializer.java b/app/src/main/java/de/timroes/axmlrpc/serializer/StringSerializer.java index 1ef1ee9e..8712a486 100644 --- a/app/src/main/java/de/timroes/axmlrpc/serializer/StringSerializer.java +++ b/app/src/main/java/de/timroes/axmlrpc/serializer/StringSerializer.java @@ -11,21 +11,12 @@ import org.w3c.dom.Element; */ public class StringSerializer implements Serializer { - private boolean decodeStrings; private boolean encodeStrings; - public StringSerializer(boolean encodeStrings, boolean decodeStrings) { - this.decodeStrings = decodeStrings; + public StringSerializer(boolean encodeStrings) { this.encodeStrings = encodeStrings; } - public Object deserialize(Element content) throws XMLRPCException { - String text = XMLUtil.getOnlyTextContent(content.getChildNodes()); - if(decodeStrings) { - text = text.replaceAll("<", "<").replaceAll("&", "&"); - } - return text; - } public XmlElement serialize(Object object) { String content = object.toString(); diff --git a/app/src/main/java/de/timroes/axmlrpc/serializer/StructSerializer.java b/app/src/main/java/de/timroes/axmlrpc/serializer/StructSerializer.java index 87fa9615..82333829 100644 --- a/app/src/main/java/de/timroes/axmlrpc/serializer/StructSerializer.java +++ b/app/src/main/java/de/timroes/axmlrpc/serializer/StructSerializer.java @@ -19,65 +19,6 @@ public class StructSerializer implements Serializer { private static final String STRUCT_NAME = "name"; private static final String STRUCT_VALUE = "value"; - public Object deserialize(Element content) throws XMLRPCException { - - Map map = new HashMap(); - - Node n, m; - String s; - Object o; - for(int i = 0; i < content.getChildNodes().getLength(); i++) { - - n = content.getChildNodes().item(i); - - // Strip only whitespace text elements and comments - if((n.getNodeType() == Node.TEXT_NODE - && n.getNodeValue().trim().length() <= 0) - || n.getNodeType() == Node.COMMENT_NODE) - continue; - - if(n.getNodeType() != Node.ELEMENT_NODE - || !STRUCT_MEMBER.equals(n.getNodeName())) { - throw new XMLRPCException("Only struct members allowed within a struct."); - } - - // Grep name and value from member - s = null; o = null; - for(int j = 0; j < n.getChildNodes().getLength(); j++) { - m = n.getChildNodes().item(j); - - // Strip only whitespace text elements and comments - if((m.getNodeType() == Node.TEXT_NODE - && m.getNodeValue().trim().length() <= 0) - || m.getNodeType() == Node.COMMENT_NODE) - continue; - - if(STRUCT_NAME.equals(m.getNodeName())) { - if(s != null) { - throw new XMLRPCException("Name of a struct member cannot be set twice."); - } else { - s = XMLUtil.getOnlyTextContent(m.getChildNodes()); - } - } else if(m.getNodeType() == Node.ELEMENT_NODE && STRUCT_VALUE.equals(m.getNodeName())) { - if(o != null) { - throw new XMLRPCException("Value of a struct member cannot be set twice."); - } else { - o = SerializerHandler.getDefault().deserialize((Element)m); - } - } else { - throw new XMLRPCException("A struct member must only contain one name and one value."); - } - - } - - map.put(s, o); - - } - - return map; - - } - public XmlElement serialize(Object object) { XmlElement struct = new XmlElement(SerializerHandler.TYPE_STRUCT);