|
Para usar XML la forma mas facil es usar DOM. En DOM, un archivo XML es llevado a un objeto en memoria de tipo Document y con funciones se puede "navegar" por el contenido.
Ahora, normalmente, el codigo que accede a la informacion de un XML con DOM puede ser asi:
public void procesa(String parameterXML) {
DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
StringReader reader = new StringReader(parameterXML);
InputSource source = new InputSource(reader);
Document document = docBuilder.parse(source);
NodeList nl = doc.getChildNodes();
Node n1 = nl.item(0);
Node n2 = n1.getChildNodes().item(2);
Node n3 = n2.getChildNodes().item(1);
Node n4 = n3.getChildNodes().item(1);
String origen = n4.getChildNodes().item(0).getNodeValue();
String destino= n4.getChildNodes().item(1).getNodeValue();
}
Este codigo tiene varios problemas, entre ellos:
#Los hijos de un nodo pueden ser valores o comentarios o espacios en blanco entre otros tags
#La posicion de un hijo no es fija por que hay elementos opcionales o con repeticiones
Ahora, para usar funciones que sirvan en el futuro como referencia es importante esforzarse en crear aquellas funciones que representen lo que uno quiere. Esto a veces significa proponer una especificacion que ayude a resolver el problema:
En este caso:
0) Aislarse de los detalles de implementacion de parsers de XML. Solucion:
/**
* Transforma a document un String con el XML
*/
private Document getDocumentFromXML(String parameterXML)
throws ParserConfigurationException, SAXException, IOException {
DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
StringReader reader = new StringReader(parameterXML);
InputSource source = new InputSource(reader);
Document document = docBuilder.parse(source);
return document;
}
1) Los hijos de un nodo pueden ser valores o comentarios o espacios en blanco entre otros tags. Solucion:
/**
* Retorna la primera aparicion de un nodo hijo con el tipo indicado.
* @param n Nodo desde el cual buscar
* @param type tipo del hijo buscado (tag) segun las constantes de la clase Node.
*/
static Node getChildByType(Node n, int type) {
NodeList nl = n.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node t = nl.item(i);
if (t.getNodeType() == type)
return t;
}
return null;
}
2) A veces se requiere encontrar un hijo, pero su posicion no esta clara debido a que hay comentarios u otros tags opcionales en la lista. Solucion: buscar por el nombre del tag
/**
* Retorna la primera aparicion de un nodo hijo con el nombre indicado.
* @param n Nodo desde el cual buscar
* @param name nombre del hijo buscado (tag)
*/
static Node getChildByName(Node n, String name) {
NodeList nl = n.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node t = nl.item(i);
if (t.getNodeName().equals(name))
return t;
}
return null;
}
3) En muchos casos se requiere obtener un nodo que tiene un camino dentro del XML y es mas facil especificar el camino como si fuera un PATH de S.O.: PRoject/Color/Default/Task/Line. Solucion:
/**
* Retorna la primera aparicion de un nodo con el path indicado.
* @param n Documento desde el cual buscar (raiz)
* @param name path del nodo buscado con nodos separados por slash (/)
*/
static Node getElementByPath(Document doc, String path) {
StringTokenizer st = new StringTokenizer(path, "/");
Node n = doc;
while (st.hasMoreTokens()) {
String t = st.nextToken();
n = getChildByName(n, t);
if (n == null)
return null;
}
return n;
}
4) Normalmente la mayoria de las preguntas sobre XML cuando se usa DOM tienen que ver con texto y contenido, para codificar rapidamente se requiren funciones cercanas a lo necesario. Solucion:
/**
* Retorna la primera aparicion de un nodo con el path indicado.
* @param n Documento desde el cual buscar (raiz)
* @param name path del nodo buscado con nodos separados por slash (/)
*/
static String getElementText(Document doc, String path) {
Node n = getElementByPath(doc, path);
Node v = getChildByType(n, Node.TEXT_NODE);
return v.getNodeValue();
}
Finalmente
Ejemplo de la aplicacion del codigo anterior:
/**
* Genera un nombre concatenando nombre y apellido del XML
*/
private String getName(String paramXML){
Documento document = getDocumentFromXML(paramXML);
String fileName = null;
String nombre = getElementText(document,
"Empresa/Administrador/Nombre");
String apellido = getElementText(document,
"Empresa/Administrador/Apellido");
return nombre.trim() +" "+ destino.trim();
}
Notas
- falla si el elemento Empresa se repite ??
- falla si Administrador es opcional?
|