#!/usr/bin/env python
# encoding: iso-8859-15
#
#Minë. Mundo Interactivo-Narrativo en Español [Tierra-Media]
#Copyright (C) 2002  Pablo Ruiz Múzquiz
#
#
#This program is free software; you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation; either version 2 of the License, or
#(at your option) any later version.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
#
#Fichero: xmlutils.py

"""Utilidades para manejar más cómodamente ficheros XML."""

from xml.dom import minidom


def parsear_fichero(path):
    """Abre un fichero XML, lo analiza y devuelve el elemento raíz.

    Parametros:
      path: nombre y ruta completa del fichero
    Requiere:
      path != None
    Asegura:
      return != None
    """
    arbol_xml = minidom.parse(path)
    elem_raiz = arbol_xml.documentElement
    return elem_raiz


def subelementos(elem, nombre = None):
    """Devuelve una lista con todos los subelementos con el nombre indicado.
    Si no se indica nombre, devuelve todos los subelementos.

    Parametros:
      elem(xml.dom.minidom.Node): una instancia de elemento XML
      nombre(string): nombre de los subelementos a buscar
    Requiere:
      elem != None
    Asegura:
      return != None
    """
    if nombre != None:
	return elem.getElementsByTagName(nombre)
    else:
	return [elem for elem in elem.childNodes
                if elem.nodeType == minidom.Node.ELEMENT_NODE]


def subelemento(elem, nombre = None):
    """Devuelve el primer subelemento con el nombre indicado.
    Si no se indica nombre, devuelve el primer subelemento.

    Parametros:
      elem(xml.dom.minidom.Node): una instancia de elemento XML
      nombre(string): nombre del subelemento a buscar
    Requiere:
      elem != None
      nombre != None -> existe al menos un subelemento con ese nombre
      nombre == None -> existe al menos un subelemento
    Asegura:
      return != None
    """
    return subelementos(elem, nombre)[0]


def es_elemento(elem):
    """Indica si el nodo es un elemento normal de XML.

    Es decir, un <nombre .../> (y no un texto, un comentario, etc.)
    """
    return elem.nodeType == minidom.Node.ELEMENT_NODE


def nombre_elemento(elem):
    """Extrae el nombre del tag de un elemento.

    Parametros:
      elem(xml.dom.minidom.Node): una instancia de elemento XML     
    Requiere:
      elem != None
    Asegura:
      return != None
    """
    return elem.nodeName.encode('ISO-8859-15')


def contenido(elem):
    """Extrae todo el texto contenido dentro del elemento.

    Parametros:
      elem(xml.dom.minidom.Node): una instancia de elemento XML
    Requiere:
      elem != None
    Asegura:
      return != None
    """
    contenido = ""
    for sub_elem in elem.childNodes:
        if sub_elem.nodeType == minidom.Node.TEXT_NODE:
            contenido = contenido + sub_elem.data.encode('ISO-8859-15')
    return contenido


def atributo(elem, nombre):
    """Extrae el valor de un atributo del elemento.
    Si el elemento no contiene el atributo, produce una excepcion KeyError.

    Parametros:
      elem(xml.dom.minidom.Node): una instancia de elemento XML
      nombre(string): el nombre del atributo a extraer
    Requiere:
      elem != None
      nombre != None
    Asegura:
      return != None
    """
    return elem.attributes[nombre].value.encode('ISO-8859-15')


def atributo_def(elem, nombre, valor_defecto):
    """Extrae el valor de un atributo del elemento, con valor por defecto.

    Parametros:
      elem(xml.dom.minidom.Node): una instancia de elemento XML
      nombre(string): el nombre del atributo a extraer
      valor_defecto(any): el valor devuelto si no existe
    Requiere:
      elem != None
      nombre_atributo != None
    """
    if elem.hasAttribute(nombre):
	return atributo(elem, nombre)
    else:
	return valor_defecto


def atributo_int(elem, nombre, error_msg):
    """Extrae el valor de un atributo del elemento y lo convierte a número entero.
    Si el elemento no contiene el atributo, produce una excepcion KeyError.
    Si el valor no es convertible a entero, produce una excepcion ValueError
    con el texto de error indicado.

    Parametros:
      elem(xml.dom.minidom.Node): una instancia de elemento XML
      nombre(string): el nombre del atributo a extraer
      error_msg(string): error a mostrar si el valor no es entero
    Requiere:
      elem != None
      nombre_atributo != None
      error_msg != None
    Asegura:
      return != None
    """
    valor = atributo(elem, nombre)
    try:
	valor_int = int(valor)
	return valor_int
    except ValueError:
	raise ValueError(error_msg)


def atributo_int_def(elem, nombre, valor_defecto, error_msg):
    """Extrae el valor de un atributo del elemento, con valor por defecto, y lo
    convierte a número entero.
    Si el valor no es convertible a entero, produce una excepcion ValueError
    con el texto de error indicado.

    Parametros:
      elem(xml.dom.minidom.Node): una instancia de elemento XML
      nombre(string): el nombre del atributo a extraer
      valor_defecto(int): el valor devuelto si no existe
      error_msg(string): error a mostrar si el valor no es entero
    Requiere:
      elem != None
      nombre != None
      valor_defecto != None
      error_msg != None
    Asegura:
      return != None
    """
    if elem.hasAttribute(nombre):
	return atributo_int(elem, nombre, error_msg)
    else:
	return valor_defecto


def atributo_float(elem, nombre, error_msg):
    """Extrae el valor de un atributo del elemento y lo convierte a número float.
    Si el elemento no contiene el atributo, produce una excepcion KeyError.
    Si el valor no es convertible a float, produce una excepcion ValueError
    con el texto de error indicado.

    Parametros:
      elem(xml.dom.minidom.Node): una instancia de elemento XML
      nombre(string): el nombre del atributo a extraer
      error_msg(string): error a mostrar si el valor no es float
    Requiere:
      elem != None
      nombre_atributo != None
      error_msg != None
    Asegura:
      return != None
    """
    valor = atributo(elem, nombre)
    try:
	valor_float = float(valor)
	return valor_float
    except ValueError:
	raise ValueError(error_msg)


def atributo_float_def(elem, nombre, valor_defecto, error_msg):
    """Extrae el valor de un atributo del elemento, con valor por defecto, y lo
    convierte a número float.
    Si el valor no es convertible a float, produce una excepcion ValueError
    con el texto de error indicado.

    Parametros:
      elem(xml.dom.minidom.Node): una instancia de elemento XML
      nombre(string): el nombre del atributo a extraer
      valor_defecto(float): el valor devuelto si no existe
      error_msg(string): error a mostrar si el valor no es float
    Requiere:
      elem != None
      nombre != None
      valor_defecto != None
      error_msg != None
    Asegura:
      return != None
    """
    if elem.hasAttribute(nombre):
	return atributo_float(elem, nombre, error_msg)
    else:
	return valor_defecto

