Está en la página 1de 12

Articulo 0012

http://www.gixml.com
15 de septiembre de 2001

GIXML.COM
Programe su propio editor de XML en Visual Basic
Juan Jos Riera Esteban. Grupo de Inters en XML.

Septiembre 2001

Material reproducido para fines acadmicos, prohibida su reproduccin sin la autorizacin de los titulares de los derechos. 2001 Copyright GIXML. http://www.gixml.com

Programe su propio editor de XML en Visual Basic


Juan Jos Riera. Phoenix/Linx casa de software Gixml.com. jujorie@hotmail.com

Abstracto
Es posible programar un pequeo editor de XML en Visual Basic para dejar de usar el Block de notas de Windows. Este pequeo editor que construiremos puede mostrar la estructura del documento en forma de rbol y su correspondiente versin en texto con etiquetas adems de realizar las tareas bsicas de inclusin, modificacin, eliminacin y consulta de nodos a travs del Modelo de objetos de documento (DOM, Document object model) . Encontrar un editor que satisfaga nuestras necesidades para la creacin de documentos XML puede ser una tarea complicada y usar el Block de notas de Windows para tal fin puede ser verdaderamente engorroso. Por tal motivo decid construir mi propio editor que me permitiera ver un documento XML en su forma de rbol y en su forma de texto con etiquetas simultneamente y que al editar el rbol los cambios se reflejen instantneamente en el texto con etiquetas y viceversa. Con este objetivo en mente me enfrasque en una pelea entre Visual Basic y el DOM y descubr que era bastante sencillo cumplir mi misin. Visual Basic ofrece un control de usuario que permite la edicin y visualizacin de datos en forma de rbol, el TreeView. Este control es el que se usa en el Explorador de Windows para mostrar las carpetas. Para nuestro fin lo usaremos para representar un documento XML.

GIXML.COM
Figura 1: los nodos a representar

XML posee distintos nodos que pueden ser representados. Dada la simplicidad de nuestro editor slo usaremos tres tipos de ellos que son el Elemento, el Atributo y el Texto.

Con los conocimientos adquiridos en este articulo podr complementar el pequeo editor para que incluya todos los tipos de nodos y agregarle caractersticas propias a su gusto o, porque no, crear un editor profesional que sea comercializable. En futuros artculos es posible que usemos este editor para ilustrar otros conceptos de XML.

Material reproducido para fines acadmicos, prohibida su reproduccin sin la autorizacin de los titulares de los derechos. 2001 Copyright GIXML. http://www.gixml.com

Requerimientos
Este documento supone que tiene conocimientos bsicos acerca de Visual Basic y XML. Para ejecutar la aplicacin requiere Visual Basic (VB) versin 5 o superior y el interpretador de XML de Microsoft versin 3.

Manos a la obra
Lo primero que debemos hacer es crear un nuevo proyecto estndar en Visual Basic. En la lista de componentes agreguemos el componente Microsoft Windows Common Controls que es donde se incluye el control TreeView. Para nuestro editor debemos incluir una forma que posea un control texto multilnea y un control TreeView con la propiedad PathSeparator establecida a / (la barra de divisin conocida tambin como slash).

GIXML.COM
Figura 2: la pantalla de nuestro editor

Hay que separar la parte de XML de la parte grfica en VB. Por ejemplo para agregar un nodo a un control TreeView es mas sencillo que agregarlo a un documento XML. Siempre hay que tener en cuenta que en para nuestro control de rbol existe un nodo raz y unos nodos hijos. Veamos como crear cada uno de los nodos.

Dim nde as Node

Nodo del control TreeView

Agrega un nodo raiz al arbol Set nde = tvwArbol.Nodes.Add( , ,padre, Nodo Padre) Agrega un nodo hijo al nodo raiz set nde = tvwArbol.Nodes.Add(padre, tvwChild, _ hijo1, Nodo Hijo) Creacin de nodos en un control TreeView

La cadena padre indica la clave del elemento padre y la cadena hijo1 indica la clave del nodo hijo. Ambas claves deben ser nicas. La relacin padre e hijo se establece cuando se crea el nodo y se especifica el primero y segundo argumento del mtodo agregar indicando la relacin padrehijo.
Material reproducido para fines acadmicos, prohibida su reproduccin sin la autorizacin de los titulares de los derechos. 2001 Copyright GIXML. http://www.gixml.com

Tambin sabemos que un documento XML tambin posee un nodo raz y unos nodos asociados a ste. Para crear un nuevo documento XML con un nodo principal podramos seguir el siguiente ejemplo.

Dim xmlDocumento as DOMDocument30 Set xmlDocumento = New DOMDocument30 Set xmlDocumento.DocumentElement = xmlDocumento.CreateElement(principal) Creacin de un nuevo documento XML

Con este cdigo se generar un documento XML con la siguiente forma: <principal/> vamos a generar un rbol como el que sigue a travs de cdigo: <correo prioridad=alta> <para>Jujorie@hotmail.com</para> <copia/> <copiaoculta/> <cuerpo> <titulo>Un saludo</titulo> saludos desde XML! </cuerpo> </correo>

GIXML.COM
Veamos el cdigo para crear este rbol con en DOM:

Material reproducido para fines acadmicos, prohibida su reproduccin sin la autorizacin de los titulares de los derechos. 2001 Copyright GIXML. http://www.gixml.com

Dim Dim Dim Dim Dim

xmlDocumento xmlNodoRaiz xmlNuevoAtributo xmlNuevoNodo xmlNodoHijo

As As As As As

DOMDocument30 IXMLDOMNode IXMLDOMAttribute IXMLDOMNode IXMLDOMNode

Set xmlDocumento = New DOMDocument30 ' Creando el nodo raiz Set xmlNodoRaiz = xmlDocumento.createElement("correo") Set xmlDocumento.documentElement = xmlNodoRaiz ' Agregar un atributo al nodo raiz Set xmlNuevoAtributo = xmlDocumento.createAttribute("prioridad") xmlNuevoAtributo.nodeTypedValue = "alta" xmlNodoRaiz.Attributes.setNamedItem xmlNuevoAtributo ' agregar los nodos hijos al nodo raiz Set xmlNuevoNodo = xmlDocumento.createElement("para") xmlNuevoNodo.nodeTypedValue = "jujorie@hotmail.com" xmlNodoRaiz.appendChild xmlNuevoNodo Set xmlNuevoNodo = xmlDocumento.createElement("copia") xmlNodoRaiz.appendChild xmlNuevoNodo Set xmlNuevoNodo = xmlDocumento.createElement("copiaoculta") xmlNodoRaiz.appendChild xmlNuevoNodo Set xmlNuevoNodo = xmlDocumento.createElement("cuerpo") xmlNodoRaiz.appendChild xmlNuevoNodo

GIXML.COM
Set xmlNuevoNodo = _ xmlDocumento.documentElement.getElementsByTagName("cuerpo").Item(0) xmlNuevoNodo.appendChild xmlNodoHijo Creando el arbol ejemplo a traves del DOM

' agregar un elemento hijo al nodo <cuerpo> Set xmlNodoHijo = xmlDocumento.createElement("titulo") xmlNodoHijo.nodeTypedValue = "Un saludo"

Cosas interesantes del fragmento de cdigo anterior es como se busca un nodo de la raz. Esto se hizo a travs del mtodo getElementsByTagName(etiqueta) el cual retorna una lista de nodos en los cuales podemos buscar cualquier elemento que nos interesa. Existen formas alternas de crear los nodos Elemento, Atributo y Texto que son las que utilizaremos para el editor. Usaremos el mtodo del DOM CreateElement. Supongamos que ubicamos un nodo cualquiera a travs del rbol como se indic antes y se desea agregar un atributo un texto y un elemento adicional. Vea lo que deseamos hacer. De un rbol: <raiz> <nodo1/> <nodo2/> <nodo3/> </raiz> a un rbol:

Material reproducido para fines acadmicos, prohibida su reproduccin sin la autorizacin de los titulares de los derechos. 2001 Copyright GIXML. http://www.gixml.com

<raiz> <nodo1/> <nodo2 atributo=un valor> texto en el nodo 2 <nodohijo/> <nodo2> <nodo3/> </raiz> La lgica para realizar la tarea es ubicar el nodo, crear el nodo atributo, elemento o texto segn el caso y agregarlo. Veamos el cdigo

' Ubiquemos el nodo Set xmlNodo = xmlDocumento.getElementsByTagName("raiz/nodo2").Item(0) ' Creemos un atributo Set xmlAtributo = xmlDocumento.createNode(2, "Atributo", "") xmlAtributo.nodeTypedValue = "Valor" xmlNodo.Attributes.setNamedItem xmlAtributo ' Creemos un nodo hijo al nodo ubicado xmlNodo.appendChild xmlDocumento.createNode(1, "nodohijo", "") Forma de agregar elementos a un rbol XML

GIXML.COM
Set xmlNodo = xmlDocumento.getElementsByTagName("raiz/nodo2").Item(0)

Note que una forma de ubicar un nodo es dndole una direccin de ruta como en los directorios de Windows. Fjese la instruccin de la lnea 2:

Se pudo omitir la parte de la ruta que dice raiz/nodo2 por solamente nodo2 pero para efectos de nuestro editor es bueno saberlo.

Y donde entra el TreeView?


Ya se haba dicho que el TreeView es capaz de representar rboles y que una forma de ubicar nodos es a travs de una ruta estilo Windows que precisamente se puede representar mediante un rbol. Asociando todas estas ideas tenemos un control que puede generar y editar rboles XML. Sabemos que podemos insertar tres tipos de nodos en el pequeo editor por lo tanto es bueno diferenciar esos tipos de nodo dentro del TreeView. Esta discriminacin la podemos asignar a travs de la propiedad Tag del objeto Node de la coleccin Nodes del control TreeView. Vamos a agregar un nuevo nodo al control y, simultneamente, creemos un nodo en el documento XML. Veamos un ejemplo de una funcin que cumple con esta tarea. La lgica bsica se basa en lo siguiente si la coleccin de nodos del control TreeView esta vaca se agrega el nodo al rbol y se crea el nodo raz del documento XML. Si la coleccin no se encuentra vaca se verifica que exista un nodo seleccionado (a travs de la propiedad SelectedItem del control TreeView) si no hay ninguno se selecciona el nodo raz de rbol. Una vez seleccionado el nodo al cual se desea agregar un componente nuevo se obtiene la ruta completa y se agrega el elemento. Esto es necesario para el documento XML, para el rbol se agrega el nodo y ya.

Material reproducido para fines acadmicos, prohibida su reproduccin sin la autorizacin de los titulares de los derechos. 2001 Copyright GIXML. http://www.gixml.com

Private Sub AgregarNuevoNodo(ByRef TreeView As TreeView, ByVal TipoNodoXML As Integer) Dim nde As Node Dim strNombreNodo As String Dim xmlNodoActual Dim xmlNuevoNodo Dim xmlAtributo As IXMLDOMNode As IXMLDOMNode As IXMLDOMAttribute

On Error GoTo Errores_AgregarNuevoNodo With TreeView strNombreNodo = "Nodo" & .Nodes.Count + 1 If .Nodes.Count = 0 Then Set mxmlDocumento.documentElement = _ mxmlDocumento.createElement(strNombreNodo) Set mndeRaizArbol = .Nodes.Add(, , mcstrClaveRaiz, strNombreNodo) mndeRaizArbol.Tag = TipoNodoXML Set .SelectedItem = mndeRaizArbol Else If .SelectedItem Is Nothing Then Set .SelectedItem = mndeRaizArbol End If Set nde = .Nodes.Add(.SelectedItem.Key, tvwChild, _ CreateUUID, strNombreNodo) nde.EnsureVisible nde.Tag = TipoNodoXML Set xmlNodoActual = _ mxmlDocumento.getElementsByTagName(.SelectedItem.FullPath).Item(0) Set xmlNuevoNodo = mxmlDocumento.createNode(TipoNodoXML, _ strNombreNodo, )

GIXML.COM
Select Case TipoNodoXML Case mcintXMLNodo xmlNodoActual.appendChild xmlNuevoNodo Case mcintXMLAtributo xmlNuevoNodo.nodeTypedValue = "Valor" xmlNodoActual.Attributes.setNamedItem xmlNuevoNodo Case mcintXMLTexto xmlNuevoNodo.Text = "NuevoTexto" nde.Text = xmlNuevoNodo.Text xmlNodoActual.insertBefore xmlNuevoNodo, xmlNodoActual.firstChild End Select End If End With Exit Sub Errores_AgregarNuevoNodo: MsgBox Err.Description, vbExclamation, "Error N " & Err End Sub Cdigo para agregar un nodo al rbol y al documento XML.

Esta funcin coloca un nombre genrico al nuevo nodo el cual indica su posicin en la coleccin. La lgica que tiene que ver con el rbol se coloc primero y la lgica que tiene que ver con el documento XML est despus. En el cdigo existe una referencia a una funcin CreateUUID la cual retorna un valor universal nico. Se basa en una llamada del API de Windows y se usa principalmente para asignar un valor nico a cada nodo del rbol. Ya tenemos una primer bloque de cdigo el cual agrega nodos al rbol y elementos al documento. Ahora viene la parte que permite editar. La estructura se fundamenta en ubicar el nodo

Material reproducido para fines acadmicos, prohibida su reproduccin sin la autorizacin de los titulares de los derechos. 2001 Copyright GIXML. http://www.gixml.com

seleccionado del rbol. Obtener su ruta si se trata de un nodo que representa un elemento u obtener la ruta de su padre si el nodo representa un Texto o un atributo del documento XML. Si se trata de un nodo tipo elemento se crea un nuevo nodo con el nombre editado y se le agregan los elementos hijos del elemento que se esta editando incluyendo los atributos. Si se trata de un nodo atributo, se crea un nuevo atributo con el nombre que se acaba de cambiar, se retira el atributo cambiado y se agrega el nuevo. Para un nodo texto se cambia el texto y ya. Estas funciones se pueden ubicar en el evento AfterLabelEdit del control TreeView. Veamos el listado:

Private Function CambiarNombreNodo(ByVal Ruta As String, ByVal NuevoNombre As String) As Boolean Dim strNombreNodo As String, intNodos As Integer Dim xmlNodoActual Dim xmlNuevoNodo Dim xmlAtributoNuevo As IXMLDOMNode As IXMLDOMNode As IXMLDOMAttribute

On Error GoTo Errores_CambiarNombreNodo CambiarNombreNodo = True Set xmlNodoActual = mxmlDocumento.getElementsByTagName(Ruta).Item(0) ' Copiando los nodos hijos del nodo que se desea ' cambiar de nombre Set xmlNuevoNodo = mxmlDocumento.createNode(xmlNodoActual.nodeType, _ NuevoNombre, vbNullString) For intNodos = 0 To xmlNodoActual.childNodes.length - 1 xmlNuevoNodo.appendChild xmlNodoActual.childNodes(intNodos).cloneNode(True) Next

GIXML.COM
' Copiando los atributos del nodo que se desea ' cambiar de nombre Do While xmlNodoActual.Attributes.length > 0 strNombreNodo = xmlNodoActual.Attributes.Item(0).nodeName Set xmlAtributoNuevo = xmlNodoActual.Attributes.removeNamedItem(strNombreNodo) xmlNuevoNodo.Attributes.setNamedItem xmlAtributoNuevo Loop ' Intercambiar la copia del nodo con el nuevo nombre ' con el nodo anterior If xmlNodoActual.parentNode Is Nothing Then Set mxmlDocumento.documentElement = xmlNuevoNodo Else xmlNodoActual.parentNode.replaceChild xmlNuevoNodo, xmlNodoActual End If Exit Function Errores_CambiarNombreNodo: CambiarNombreNodo = False MsgBox Err.Description, vbExclamation, "Error N " & Err End Function Funcion para cambiar el nombre a un nodo elemento

Material reproducido para fines acadmicos, prohibida su reproduccin sin la autorizacin de los titulares de los derechos. 2001 Copyright GIXML. http://www.gixml.com

Private Function CambiarNombreAtributo(ByVal RutaNodoPadre As String, _ ByVal NombreAnterior As String, _ ByVal NuevoNombre As String _ ) As Boolean Dim xmlNodoActual Dim xmlAtributoActual Dim xmlAtributoNuevo As IXMLDOMNode As IXMLDOMAttribute As IXMLDOMAttribute

On Error GoTo Errores_CambiarNombreAtributo CambiarNombreAtributo = True Set xmlNodoActual = mxmlDocumento.getElementsByTagName(RutaNodoPadre).Item(0) Set xmlAtributoActual = xmlNodoActual.Attributes.getNamedItem(NombreAnterior) Set xmlAtributoNuevo = mxmlDocumento.createAttribute(NuevoNombre) xmlAtributoNuevo.Value = xmlAtributoActual.Value xmlNodoActual.Attributes.removeNamedItem xmlAtributoActual.Name xmlNodoActual.Attributes.setNamedItem xmlAtributoNuevo Exit Function Errores_CambiarNombreAtributo: CambiarNombreAtributo = False MsgBox Err.Description, vbExclamation, "Error N " & Err End Function Funcin para cambiar el nombre a un nodo Atributo

GIXML.COM
En el evento AfterLabelEdit se coloca el siguiente cdigo para ejecutar la edicin:
Private Sub tvwArbolXML_AfterLabelEdit(Cancel As Integer, NewString As String) Dim strRutaNodo As String Dim xmlNodoActual As IXMLDOMNode With tvwArbolXML Select Case .SelectedItem.Tag Case mcintXMLNodo Cancel = Not CambiarNombreNodo(.SelectedItem.FullPath, NewString) Case mcintXMLAtributo Cancel = Not CambiarNombreAtributo(.SelectedItem.Parent.FullPath, _ .SelectedItem.Text, NewString) Case mcintXMLTexto strRutaNodo = .SelectedItem.Parent.FullPath Set xmlNodoActual = _ mxmlDocumento.getElementsByTagName(strRutaNodo).Item(0) xmlNodoActual.Text = NewString End Select End With MostrarXML End Sub Muestra el documento en el control texto Cdigo del evento AfterLabelEdit del control TreeView

Material reproducido para fines acadmicos, prohibida su reproduccin sin la autorizacin de los titulares de los derechos. 2001 Copyright GIXML. http://www.gixml.com

Ya somos capaces de editar ahora el cdigo para eliminar es muy sencillo. Se ubica la ruta del nodo elemento o la ruta del nodo padre del nodo atributo o el nodo texto y se suprime mediante el mtodo adecuado. Para el rbol es simplemente una llamada a un mtodo

Dim strRutaNodo As String Dim xmlNodoActual As IXMLDOMNode With tvwArbolXML If .SelectedItem Is Nothing Then Exit Sub Select Case .SelectedItem.Tag Case mcintXMLNodo strRutaNodo = .SelectedItem.FullPath Set xmlNodoActual = _ mxmlDocumento.getElementsByTagName(strRutaNodo).Item(0) xmlNodoActual.parentNode.removeChild xmlNodoActual Case mcintXMLAtributo strRutaNodo = .SelectedItem.Parent.FullPath Set xmlNodoActual = _ mxmlDocumento.getElementsByTagName(strRutaNodo).Item(0) xmlNodoActual.Attributes.removeNamedItem .SelectedItem.Text Case mcintXMLTexto strRutaNodo = .SelectedItem.Parent.FullPath Set xmlNodoActual = _ mxmlDocumento.getElementsByTagName(strRutaNodo).Item(0) xmlNodoActual.Text = vbNullString

GIXML.COM
End Select .Nodes.Remove .SelectedItem.Key End With Como eliminar un nodo en el rbol y en el documento XML.

Muy bien ya tenemos un documento XML y ahora cmo se almacena?. La respuesta es simple, se llama al mtodo Save del de la clase DOMDocument30 y listo. El argumento del mtodo indica el nombre y la ruta donde se desea almacenar el documento.

Recuperar un documento XML


La parte mas compleja de nuestro editor radica en como representar en el rbol un documento XML que existe y ha sido guardado en disco. La forma en que se realiz esta tarea es mediante una funcin recursiva que recorre todos los nodos hijos de cada nodo hasta encontrar los nodos terminales podemos verlo en seudo cdigo como: Recorrer(NodoActual) Si no esta vacio NodoActual Imprimir nodo Para cada nodo n en nodo.NodosHijos Recorrer nodo.NodosHijos.Item(n) Fin para Fin si Ahora que sabemos como funciona veamos el cdigo real. Previo a la llamada de la funcin CargarArbol se debe cargar el documento XML como se indico al principio. Esto podra ser algo como esto:

Material reproducido para fines acadmicos, prohibida su reproduccin sin la autorizacin de los titulares de los derechos. 2001 Copyright GIXML. http://www.gixml.com

strArchivo = FileDialog(hWnd, Filtro:=mcstrFiltroDialogo, Extension:="xml") If strArchivo <> vbNullString Then If mxmlDocumento.Load(strArchivo) Then MostrarXML CargarArbol tvwArbolXML, mxmlDocumento.firstChild End If End If

Luego se procede con la funcin que representar el rbol dentro del control TreeView:
Private Sub CargarArbol(TreeView As TreeView, _ Nodo As IXMLDOMNode, _ Optional ByVal Padre As String) Dim xmlNodoActual As IXMLDOMNode, nde As Node, intNodos As Integer If Nodo Is Nothing Then Exit Sub Condicin de parada

If Padre = vbNullString Then es el primer nodo de la coleccion TreeView.Nodes.Clear Set nde = TreeView.Nodes.Add(, , mcstrClaveRaiz) Else Set nde = TreeView.Nodes.Add(Padre, tvwChild, CreateUUID) End If

GIXML.COM
Select Case Nodo.nodeType Case mcintXMLNodo nde.Text = Nodo.nodeName Case mcintXMLTexto nde.Text = Nodo.Text Exit Sub Los nodo tipo texto no tienen nodos hijos Case mcintXMLAtributo nde.Text = Nodo.nodeName Exit Sub los nodos tipo atributo no tienen nodos hijos End Select Llamada recursiva para cada uno de los hijos For intNodos = 0 To Nodo.childNodes.length - 1 CargarArbol TreeView, Nodo.childNodes.Item(intNodos), Padre Next Llamada recursiva para cargar los atributos If Not Nodo.Attributes Is Nothing Then For intNodos = 0 To Nodo.Attributes.length - 1 CargarArbol TreeView, Nodo.Attributes.Item(intNodos), Padre Next End If End Sub Forma de representar un documento XML en un control TreeView

Padre = nde.Key nde.EnsureVisible nde.Tag = Nodo.nodeType

Conclusin
Se ha podido ver con este articulo lo sencillo que es trabajar con el DOM y XML. Es posible que los conocimientos aqu adquiridos sirvan para dar ideas acerca de nuevas aplicaciones cuyos depsitos de datos puedan ser documentos XML. Como el DOM es estndar entre plataformas es
Material reproducido para fines acadmicos, prohibida su reproduccin sin la autorizacin de los titulares de los derechos. 2001 Copyright GIXML. http://www.gixml.com

posible crear un editor XML en JavaScript, en Java o en VBScript y hacerlo transportable entre plataformas. Otro uso que podramos dar a este manejo del DOM de XML es para hacer una aplicacin que defina datos o esquemas para ser usados por otras aplicaciones. En fin hay un sin numero de aplicaciones que con algo de imaginacin se pueden generar.

Enlaces de inters
Para obtener informacin acerca de Visual Basic: http://msdn.microsoft.com/vbasic/ Para obtener el interpretador de XML versin 3: www.microsoft.com/xml Para obtener la documentacin acerca del modelo objetos del interpretador de XML: http://msdn.microsoft.com/downloads/default.asp?url=/downloads/topic.asp?url=/msdnfiles/028/000/072/topic.xml Para obtener informacin acerca de XML: www.xml.com o www.xml101.com Si desean una versin completa del cdigo del editor, envenme un correo a la direccin JuJoRiE@Hotmail.com

Acerca del Autor


Juan Jos Riera Esteban es jefe de programadores de Phoenix/Linx Casa de Software, una empresa que se especializa en software administrativo para la pequea y mediana industria. JuJoRiE@Hotmail.com

GIXML.COM

Material reproducido para fines acadmicos, prohibida su reproduccin sin la autorizacin de los titulares de los derechos. 2001 Copyright GIXML. http://www.gixml.com

También podría gustarte