- Inmutabilidad
- Acceso a subnodos por invocaciones encadenadas, evitando NPE ante nodos inexistentes
El segundo punto se basa en el patrón Null Object: la idea es prescindir de null en el API para evitar el fatídico Null Pointer Exception. Más abajo lo vemos.
Como dije antes la librería es elemental, y sus limitaciones son:
- No sirve para "recorrer" el XML sino para obtener elementos conocidos
- No accede a los atributos de los elementos
API de XmlNode
Esta es la firma de los constructores:
public XmlNode(); public XmlNode(Node node); public XmlNode(Document doc);El primero es el Null Object, y si bien es un constructor público, lo normal será que sólo se utilice desde la misma clase y no desde afuera. El segundo toma un Node y el tercero un Document. Este último toma el nodo raiz del documento. La idea es que podamos partir de un documento o un nodo cualquiera, y olvidarnos de la diferenciación: lo que tenemos es un árbol de nodos.
public String getName();
public String getValue();
Con estos métodos obtenemos el nombre (tag) y el valor (contenido) del nodo. Ambos retornarán null si es un Null Object.
public XmlNode subNode(String tagName);
Este método en cambio nunca retorna null y permite invocaciones encadenadas. El argumento debe ser un tag de un nodo hijo (inmediatamente relacionado con el actual). Veamos un ejemplo. Si creamos un XmlNode a partir de esto:
<a> <b> <c>hola</c> <d>que tal</d> </b> </a>
Podremos accederlo así:
String nombre = nodo.getName(); // "a"
XmlNode nodoB = nodo.subNode("b"); // subnodo <b>
XmlNode nodoC = nodo.subNode("b").subNode("c"); // subnodo <c>
String valor1 = nodo.subNode("b").subNode("d").getValue(); // "que tal"
String valor2 = nodoC.getValue(); // "hola"
Y también así:
XmlNode nodoX = nodo.subNode("z").subNode("y").subNode("x");
String valor3 = nodoX.getValue(); // null
Ahí vemos la invocación encadenada con nodos inexistentes. En nodoX nos quedó un Null Object. Para verificar si el XmlNode "está definido" o es nulo, tenemos también el siguiente método (inspirado en el homónimo de Option en Scala):
public boolean isDefined();
Así será más prolijo verificar si el nodo existe, en lugar de ver si getName() o getValue() retornan null.
El código
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class XmlNode
{
protected Node node = null;
public XmlNode()
{
}
public XmlNode(Node node)
{
this.node = node;
}
public XmlNode(Document doc)
{
this.node = doc.getDocumentElement();
}
public XmlNode subNode(String tagName)
{
if(node != null)
{
NodeList nl = node.getChildNodes();
for(int i = 0; i < nl.getLength(); i++)
{
Node n = nl.item(i);
if(n.getNodeName().equals(tagName))
{
return new XmlNode(n);
}
}
}
return new XmlNode();
}
public String getName()
{
return !this.isDefined()? null : node.getNodeName();
}
public String getValue()
{
return !this.isDefined()? null : node.getFirstChild().getNodeValue();
}
public boolean isDefined()
{
return this.node != null;
}
}
0 comments:
Publicar un comentario en la entrada