Documentos de Académico
Documentos de Profesional
Documentos de Cultura
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
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.
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
As As As As As
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.
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.
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
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
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