Creando un visor de XML (Parte I)

En este artículo se describe el proceso de desarrollo de una pequeña herramienta que permitirá formatear un documento XML haciendo que resulte más legible, mostrarlo mediante un árbol, y seleccionar nodos mediante XPath visualizando aquéllos que respondan a la expresión de búsqueda resaltados. Adicionalmente se le añadirán otras características secundarias como el guardar y cargar ficheros, una lista de archivos recientes, ajuste de línea y expansión y contracción de todos los nodos del árbol. Es una herramienta sencilla pero que puede ser bastante útil para trabajar con XML.

Debido a sus dimensiones, este artículo ha sido dividido en dos partes. Se puede consultar la segunda parte en la siguiente dirección.

El resultado final de la aplicación mostrando sus tres vistas será el siguiente:

 

(Pulsad la imagen para verla a tamaño real)
Visor
Visor XML. Texto sin formatear.

 

(Pulsad la imagen para verla a tamaño real)
Visor
Visor XML. Vista en árbol.

 

(Pulsad la imagen para verla a tamaño real)
Visor
Visor XML. Texto formateado.

 

FORMATEANDO EL DOCUMENTO XML:

El código para formatear el texto se basa en dos funciones. La primera de ellas se llama FormatearTexto y se encargará de inicializar las variables, cargar el texto introducido en el primer RichTextBox en una variable del tipo XmlDocument. Esta primera función llamará a la segunda (IndentarXML), la cual es una función recursiva que se llamará así misma por cada nodo que tenga el arbol XML.

VB.NET:
  1. Private Sub FormatearTexto(ByVal consultar As Boolean)
  2.         Dim arbol As New Xml.XmlDocument
  3.         Dim profundidad As Integer
  4.         Dim cad As String
  5.  
  6.         'Utilizados solo para hacer la consulta
  7.         Dim nodosSeleccionados As Xml.XmlNodeList
  8.         Dim inicioNodosSeleccionados As ArrayList
  9.         Dim finalNodosSeleccionados As ArrayList
  10.         Dim i As Integer
  11.  
  12.         Try
  13.             arbol.LoadXml(rtxtXML.Text)
  14.  
  15.             profundidad = 0
  16.             cad = ""
  17.             rtxtTextoFormateado.Text = ""
  18.  
  19.             If arbol.FirstChild.NodeType = Xml.XmlNodeType.XmlDeclaration Then
  20.                 cad &= arbol.FirstChild.OuterXml & vbCr
  21.             End If
  22.             If consultar Then
  23.                 nodosSeleccionados = arbol.SelectNodes(txtConsulta.Text)
  24.                 inicioNodosSeleccionados = New ArrayList
  25.                 finalNodosSeleccionados = New ArrayList
  26.                 IndentarXML(arbol.DocumentElement, cad, 0, nodosSeleccionados, inicioNodosSeleccionados, finalNodosSeleccionados)
  27.                 rtxtTextoFormateado.Text = cad
  28.                 For i = 0 To inicioNodosSeleccionados.Count - 1
  29.                     rtxtTextoFormateado.Select(CInt(inicioNodosSeleccionados(i)), CInt(finalNodosSeleccionados(i)) - CInt(inicioNodosSeleccionados(i)))
  30.                     rtxtTextoFormateado.SelectionColor = Color.Blue
  31.                     rtxtTextoFormateado.SelectionFont = fuenteNegritaRTXT
  32.                 Next
  33.             Else
  34.                 IndentarXML(arbol.DocumentElement, cad, profundidad)
  35.                 rtxtTextoFormateado.Text = cad
  36.             End If
  37.         Catch ex As Exception
  38.             MsgBox("Se ha producido el siguiente error:" & vbCrLf & vbCrLf & " - " & ex.Message)
  39.         End Try
  40.     End Sub
  41.  
  42.     Private Function IndentarXML(ByVal nodo As Xml.XmlNode, ByRef cad As String, ByVal profundidad As Integer, Optional ByVal nodosSeleccionados As Xml.XmlNodeList = Nothing, Optional ByVal inicioNodosSeleccionados As ArrayList = Nothing, Optional ByVal finalNodosSeleccionados As ArrayList = Nothing) As String
  43.         Dim hijo As Xml.XmlNode
  44.         Dim atr As Xml.XmlAttribute
  45.  
  46.         If nodo.NodeType <> Xml.XmlNodeType.Text And nodo.NodeType <> Xml.XmlNodeType.Comment Then
  47.             'cad &= New String(Chr(9), profundidad)
  48.             cad &= New String(" "c, profundidad * 7)
  49.  
  50.             If Not nodosSeleccionados Is Nothing AndAlso estaSeleccionado(nodo, nodosSeleccionados) Then
  51.                 If cad = "" Then
  52.                     inicioNodosSeleccionados.Add(0)
  53.                 Else
  54.                     inicioNodosSeleccionados.Add(cad.Length - 1)
  55.                 End If
  56.  
  57.             End If
  58.  
  59.             cad &= "<" & nodo.Name
  60.             For Each atr In nodo.Attributes
  61.                 cad &= " " & atr.Name & "=""" & atr.Value & """"
  62.             Next
  63.             cad &= ">"
  64.  
  65.             If Not nodosSeleccionados Is Nothing AndAlso estaSeleccionado(nodo, nodosSeleccionados) Then
  66.                 finalNodosSeleccionados.Add(cad.Length)
  67.             End If
  68.  
  69.             cad &= textoDelNodo(nodo)
  70.  
  71.             If tieneHijos(nodo) Then
  72.                 cad &= vbCr
  73.                 For Each hijo In nodo.ChildNodes
  74.                     IndentarXML(hijo, cad, profundidad + 1, nodosSeleccionados, inicioNodosSeleccionados, finalNodosSeleccionados)
  75.                 Next
  76.                 'cad &= New String(Chr(9), profundidad)
  77.                 cad &= New String(" "c, profundidad * 7)
  78.             End If
  79.             cad &= "</" & nodo.Name & ">" & vbCr
  80.         End If
  81.     End Function

La función "FormatearTexto" recibe un parámetro que indica si se está realizando una consulta o no. Si es así, se obtendrán todos los nodos seleccionados por la consulta y se crearán dos arrayList para almacenar las posiciones iniciales y finales de los nodos seleccionados, para poder posteriormente resaltarlos en el RichTextBox.

La función "IndentarXML" se encarga de transformar el nodo en cadena formateada y de llamarse a si misma recursivamente por cada hijo que tuviera el nodo. El parámetro profundidad se va incrementando en uno en cada nivel del árbol, y sirve para tabular correctamente el texto de cada nodo. Si se esta consultando y el nodo actual pertenece a los nodos seleccionados por la consulta XPath, entonces se marcará su posición inicial y final añadiéndolas a los arrayList.

Continuación
Creando un visor de XML (Parte II)

One Response to “Creando un visor de XML (Parte I)”

  1. elpibedealabama Says:

    muy guapo. está bien para probar a extraer un xpath sin tener que compilar pa ver si está bien

Leave a Reply

Antispam. Escriba la palabra 'hola' (sin comillas)