Wednesday, September 2, 2009

Xml Handling in Android

In recent years I have mostly coded in C#, so on entering the wonderful world of Android and polishing up my Java skills, I find I sorely miss some of the niftier C# language elements like indexers and properties and their proliferation throughout various .NET frameworks classes.

When it came to querying/modifying XML in Android, I found it handy to write a handful of helper methods which achieve the equivalents of the below in C#:


XmlElement XmlNode[string name]; (get)
string XmlNode.InnerText; (get)
string XmlNode.InnerText; (set)
string XmlNode.OuterText; (get)


Also, note a solution to the very annoying org.w3c.dom.Node.setNodeValue(String) problem/workaround in setInnertext().

Enjoy:



import java.io.IOException;

import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xmlpull.v1.XmlSerializer;

/**
* A class containing a collection of helper methods for common Xml node navigation/query
*
* @author Scott Powell
*/
public class XmlUtils
{
public static Element getChildByName(Element e, String name)
{
NodeList l = e.getChildNodes();
if (l == null || l.getLength() == 0)
return null; // not found

for (int i = 0; i < l.getLength(); i++)
{
Node n = l.item(i);
if ((n instanceof Element) && n.getNodeName().equals(name))
return (Element)n;
}
return null; // not found
}

public static String getInnerText(Element e)
{
NodeList l = e.getChildNodes();
if (l == null || l.getLength() == 0)
return ""; /// empty

int idx = 0;
while (idx < l.getLength())
{
if (l.item(idx).getNodeType() == Node.TEXT_NODE)
return l.item(idx).getNodeValue();
idx++;
}
return ""; // no #text node found, so return empty string
}

public static void setInnerText(Element e, String val)
{
NodeList l = e.getChildNodes();
if (l != null && l.getLength() > 0)
{
int idx = 0;
while (idx < l.getLength())
{
Node n = l.item(idx);
if (n.getNodeType() == Node.TEXT_NODE)
{
//n.setNodeValue(val); // this isn't changing value!!
Node text = e.getOwnerDocument().createTextNode(val);
e.replaceChild(text, n);
return;
}
idx++;
}
}
// no #text Node, so create one
Node text = e.getOwnerDocument().createTextNode(val);
e.appendChild(text);
}

public static void writeElementTo(Element e, XmlSerializer s) throws IOException
{
s.startTag("", e.getNodeName());
if (e.hasAttributes())
{
NamedNodeMap m = e.getAttributes();
for (int i = 0; i < m.getLength(); i++)
{
Node n = m.item(i);
s.attribute("", n.getNodeName(), n.getNodeValue());
}
}
if (e.hasChildNodes())
{
NodeList kids = e.getChildNodes();
for (int i = 0; i < kids.getLength(); i++)
{
Node n = kids.item(i);
if (n.getNodeType() == Node.ELEMENT_NODE)
writeElementTo((Element)n, s); // recursively write child element
else if (n.getNodeType() == Node.TEXT_NODE)
{
s.text(n.getNodeValue());
}
}
}

s.endTag("", e.getNodeName());
}
}

1 comment:

  1. Tnx! You helped me a lot! I am porting an app writen in c# for windows mobile to Android.

    ReplyDelete