Javascript: Accediendo a los elementos del arbol de documento

Tenemos tres formas distintas de acceder a los elementos de un documento. La primera, la mas simple y rudimentaria es utilizar DHTML. Por ejemplo si tenemos una caja de texto (input) podemos por ejemplo cambiar el valor del texto que muestra gracias a su propiedad value

Código
<form id=”formulario”>
<input name=”texto” />
<input type=”button” value=”Pulsame” onclick=”document.forms[‘formulario’].texto.value = ‘Vale, ya me has pulsado'” />
</form>

Como vemos accedemos a la propiedad forms del objeto document, que es una matriz asociativa de los formularios del documento actual, con la que se puede acceder a cada uno de estos formularios através de su identificador (el atributo id). Lo que estamos haciendo entonces es seleccionar el formulario con identificador formulario y acceder a la propiedad value del objeto texto de ese formulario para actualizar su valor.



Ahora vamos a lo que en verdad nos interesa. En DOM los documentos tienen una estructura en forma de árbol con nodos que representan elementos del documento, ya sea una etiqueta o contenido y con el objeto Document como la raíz del árbol.
Cada uno de estos elementos además de tener un tipo de objeto único al que pertenecen también implementan una interfaz llamada Node que es la que representa los nodos del árbol. El implementar esta interfaz le proporciona al objeto un conjunto de propiedades y métodos para relacionarse con el resto de los nodos del árbol y para modificar el árbol que representa al documento de manera dinámica.

Estos objetos Node pueden ser como ya hemos dicho etiquetas que se representan con objetos Element (implementan la interfaz Element), atributos representados con objetos Attr y contenido, objetos de tipo Text que como es evidente solo pueden ser nodos hojas, ya que no pueden albergar otros nodos.
Los atributos son nodos especiales, ya que no se les considera parte del árbol del documento (y por lo tanto no tienen padres ni hijos).

Por ejemplo el árbol del documento del siguiente documento html:

Código
<html>
   <head>
   </head>
   <body>
      <div>
         Hola
      </div>
   </body>
</html>

sería:

Árbol del documento

El objeto Node proporciona las siguientes propiedades para acceso a los elementos del árbol:

  • firstChild: primer hijo
  • lastChild: último hijo
  • childNodes: array de los hijos del nodo
  • parentNode: nodo padre
  • nextSibling: siguiente hijo
  • prevSibling: hijo anterior

Además nos proporciona los siguientes métodos para la manipulación de los nodos:

  • insertBefore(elementoAInsertar, elemento); insertamos el elemento elementoAInsertar antes del nodo elemento
  • replaceChild(nuevoHijo, hijoAntiguo); reemplazamos el hijo hijoAntiguo del nodo por el nodo nuevoHijo
  • removeChild(hijo); elimina el nodo hijo hijo
  • appendChild(hijo); añadimos como hijo del nodo sobre el que se llama el método el nodo hijo

Veamos un ejemplo de como se usaria esto.

Código
<html>
<head>
</head>
<body><div>
<input type=”button” value=”Pulsame” onclick=”alert(‘Esto es un ‘ + document.documentElement.lastChild.firstChild.nodeName);” />
</div>
</body>
</html>

donde document.documentElement es el nodo que representa la raiz del árbol, <html> en el caso de documentos html. Por lo tanto lo que estamos haciendo es acceder al primer hijo (firstChild) del último hijo de html. Es decir, miDiv será el elemento que se refiere al div del documento. Al usar los nodos hay que tener cuidado con cosas como las líneas en blanco, ya que algunos navegadores lo considerarían un nodo de tipo Text y otros no (por eso la etiqueta div está en la misma línea que body).

Aparte de problemas como el de los retornos de carro, el problema de recorrer el árbol del documento utilizando los métodos de la interfaz Node es que si hay cambios en la estructura del documento ya no estaremos accediendo al nodo que queríamos, con lo que al cambiar la estructura tenemos que cambiar el código del script. La otra forma de acceder a los elementos del árbol, mucho mas elegante y sencilla nos viene dada gracias a los métodos del objeto Document:

getElementById(id): devuelve el objeto que representa el elemento del documento que tiene como atributo id
getElementsByTagName(etiqueta): devuelve un array de los objetos que representan a todos los elementos del documento del tipo etiqueta

Simplemente tendríamos que añadir un atributo id a la etiqueta a la que queramos acceder y bastaría con una llamada a getElementById

Código
<html>
<head>
</head>
<body><div id=”miDiv”>
<input type=”button” value=”Pulsame” onclick=”alert(‘Esto es un ‘ + getElementById(‘miDiv’));” />
</div>
</body>
</html>

Además Document proporciona métodos para crear nuevos nodos:

  • createElement()
  • createAttribute()
  • createTextNode()

Por último vamos a ver como trabajar con los atributos de una etiqueta. La forma mas sencilla de acceder a los atributos es mediante la propiedad attributes de los nodos Element, que no es mas que una matriz de los atributos de la etiqueta correspondiente al nodo Element sobre la que se aplica; o si sabemos el nombre del atributo al que queremos acceder, mediante la propiedad del mismo nombre que tendrá el elemento que representa a la etiqueta. También podemos utilizar el método getAttribute al que se le pasa el nombre del atributo.
Para crear nuevos atributos se utiliza el método createAttribute al que se le pasa una cadena que será el nombre del atributo y mas tarde le damos un valor, o podemos utilizar setAttributeNode que toma como parámetro el nodo que queremos establecer como atributo de la etiqueta o un par de cadenas de texto representando el nombre del atributo y su valor.
Por ejemplo:

Código
<span id=”miTexto” style=”color: red;” onclick=”getElementById(‘miTexto’).setAttribute(‘style’, ‘color: blue;’);”>Mi texto</span>
<input type=”button” value=”¿Como soy?” onclick=”alert(‘Mi propiedad style vale ‘ + getElementById(‘miTexto’).getAttribute(‘style’));” />

Si hacemos click sobre el texto ‘Mi texto’ setAttribute cambiará el color a azul. Si hacemos click sobre el botón usaremos getAttribute para obtener el valor del atributo.

Mi texto

Comentarios
  1. Tengo que leerme varias veces el post para hacerme una idea lo bastante clara.
    Los nodos y los elementos para su lectura: firstChild, lastChild, etc son iguales o parecidos a la lectura de un archivo XML.
    El nodo raíz el “HTML” y tiene dos “childNodes” que son “head” y “body”.
    El “div id=’miDiv'” es un elemento hijo del “body”; en el árbol que presentas, sería el primero y único.
    Para llegar a él hay dos formas:
    O bien atravesando toda la cadena (no sé muy bien cómo sería, quizás algo parecido a lo siguiente: firsChild.nextSibling.firstChild
    El primer firstChild sería “head”
    firstChild.nextSibling sería “body”
    y firstChild.nextSiblig.firstChild se refiere al “div”)
    La segunda forma es más directa:
    getElementByld(id=”miDiv”);
    Este elemento, el “div” sólo tiene un hijo que es el “input” y, a través de él podemos acceder a sus atributos.
    No sé si he puesto bien la sintaxis, pero creo que ésta es la idea. ¿Es así?

    Responder

  2. Los nodos y los elementos para su lectura: firstChild, lastChild, etc son iguales o parecidos a la lectura de un archivo XML.

    si, te suena a la lectura de un archivo xml porque dom es un api para tratar documentos xml y sus subconjuntos… no solo paginas html
    estas propiedades estan en dom nucleo, que sirve para tratar xml y luego esta dom html que añade elementos especificos para documentos html

    El “div id=’miDiv’” es un elemento hijo del “body”; en el árbol que presentas, sería el primero y único.
    Para llegar a él hay dos formas:
    O bien atravesando toda la cadena (no sé muy bien cómo sería, quizás algo parecido a lo siguiente: firsChild.nextSibling.firstChild
    El primer firstChild sería “head”
    firstChild.nextSibling sería “body”
    y firstChild.nextSiblig.firstChild se refiere al “div”)
    La segunda forma es más directa:
    getElementByld(id=”miDiv”);
    Este elemento, el “div” sólo tiene un hijo que es el “input” y, a través de él podemos acceder a sus atributos.

    si, todo bien, solo que como yo he puesto retornos de carro y esas cosas por ejemplo tal como esta el ejemplo document.documentElement.firstChild.nextSibling.firstChild no estaria definido… por que document.documentElement.firstChild.nextSibling seria el nodo siguiente a head, que no es body, sino un retorno de carro 😕 y en otros navegadores como pasan de esas cosas si que estarias accediendo al body :uch:

    Responder

  3. Gracias, raúl. Es muy buena la información que vas poniendo en esta bitácora.

    Responder

  4. jhon alexander

    hola grupo mi pregunta es la siguiente, creo que es compleja, bueno paso a contarles.

    resulta que tengo una forma con unos checkbox, el nombre de la forma lo puedo manipular, lo que trato de hacer es recorrerla hasta llegar a los nodos hijos donde se encuentran los checkbox, pero necesito ademas de llegar a ellos saber los atributos de cada uno, como por ejemplo (name,id), ya que con estos atributos hago otras cosas adicionales que seria un paseo largo de contarles mi duda es solo esa de alli el resto lo puedo hacer.

    gracias por la ayuda

    Responder

  5. neicos

    Funciona muy bien con el Firefox, pero yto busco que tb sea compatible con Internet Explorer, el cambio de color de text y lo del boton quien soy solo van en firefox. Salu2

    Responder

  6. Muy Didactico el material, felicidades. Al igual que neicos me gustaria saber como puedo poner esto a funcionar en IE (dura tarea), para que tambien las victimas de MS puedan ver bien el contenido.

    Saludos.

    Responder

  7. Yeray

    Hola gente. A ver si pueden ayudarme. He decubierto que el IE7 (no se si los anteriores tambien) no es capaz de tratar un elemento creado dinámicamente (por ejemplo un campo de texto que creo con javascript). Para que se hagan una idea: tengo un campo de texto por HTML, aprieto un boton y por JavaScript creo otro campo de texto. Luego vuelvo a apretar el boton, y ahora me interesaría coger el valor del campo de texto que cree anteriormente; pero IE7 da un error de que no existe ese elemento.
    ¿Alguien sabe como conseguir obtener ese valor?

    Responder

  8. Daniel

    Hola grupo tengo una duda, que no me deja dormir trankilo, kisera saber una funcion equivalente al document.all- ya se ke es el document.getElementById
    pero con el document.all.ID[0].lenght accedo a todos los ID que se llaman igual en el documento HTML

    Se las dejo de tareaaa

    Responder

  9. excelente post, todo un maestro, ah al amigo que pregunto sobre como manipular los atributos de un nodo le comento que existen métodos para ello: getAttribute, setAttribute, etc. Para saber más sobre ello le recomiendo que se lean el libro que está en http://www.librosweb.es llamado “introduccion a ajax”, es totalmente gratuita la descarga en pdf y la lectura(imperdible).
    Ah y no se olviden de visitar mi web

    Responder

  10. Gracias, me ha sido de gran ayuda para entender, te citaré en mi blog

    Responder

  11. Fèlix

    Una gran ayuda, muchas grácias!!

    Responder

  12. cdsf

    no estan validados los campos

    Responder

  13. asd

    alert(“HOLA”);

    Responder

  14. Rsas

    hola interesante el articulo, y me aclarado un poco las cosas acerca de javascript, no se encuentran articulos como estos en la red, se agradece.
    Tengo una duda que me gustaria saber pero no se como me la puedes contestar, bueno ahi va.
    Si quisiera acceder a un elemnto html que aun no se a dibujado esto es posible y como lo haria, me puedes explicar esta pregunta?
    gracias
    saludos

    Responder

  15. jessan kastro

    muchas gracias , por la informacion

    Responder

  16. uriel

    Muy util. Bien explicado. Gracias por tu tiempo!

    Responder

  17. gloria

    hola necesito que me ayudeis a que salga el nombre de la etiqueta head y body, no consigo que me salga, os dejo el html y el resultado de como tiene que salir.
    documento html:

    Pagina de prueba

    Tabla de datos

    (elemento 1 1 de tabla) (elemento 1 2 de tabla) (elemento 1 3 de tabla)
    (elemento 2 1 de tabla) (elemento 2 2 de tabla) (elemento 2 3 de tabla)

    resultado: http://s2.subirimagenes.com/imagen/previo/thump_9377179captura.png

    Responder

Deja un comentario