el Guille, la Web del Visual Basic, C#, .NET y más...

Código fuente de LanConfig 2008

La clase ConfigXml

 
Publicado el 12/Ene/2008
Actualizado el 12/Ene/2008
Autor: Guillermo 'guille' Som

Este es el código fuente (en línea) de la utilidad LanConfig 2008. En esta página está el de la clase ConfigXml.



 

Introducción:

Pues eso... aunque puedes bajarte el código fuente del proyecto para Visual Basic 2008 desde la página principal de la utilidad LanConfig 2008, (que como sabes es una utilidad para manejar las configuraciones de redes que tienes instalada en tu quipo), me he decidido a publicar el código fuente de forma independiente y en línea, con idea de que puedas ver algunas de las cosas que hace la aplicación sin tener que bajarte el proyecto y verlo de forma desconectada.

En los temas relacionados te pongo los links a las diferentes partes (formularios y clases) que utiliza este proyecto.

 

'------------------------------------------------------------------------------
' Clase para manejar ficheros de configuración                      (15/Nov/05)
'
' Las secciones siempre estarán dentro de <configuration>
' al menos así lo guardará esta clase, aunque permite leer pares key / value.
' Para que se sepa que se lee de configuration,
' en el código se indica explícitamente.
'
' Basada en mi código publicado el 22/Feb/05 en:
' http://www.elguille.info/NET/dotnet/appSettings2.htm
' Pero para usarla de forma independiente de ConfigurationSettings
'
' Revisado para poder guardar automáticamente                       (21/Feb/06)
' Poder leer todas las secciones y las claves de una sección        (21/Feb/06)
' Se puede eliminar una clave (a petición de Juansa)                (15/Ene/07)
'   Si después de eliminar la clave, la sección está vacía, se borra
' Se leen correctamente las claves que están como atributos         (15/Ene/07)
' Permite leer las claves de comentarios                            (15/Ene/07)
' Se filtran más caracteres no permitidos en secciones y claves     (15/Ene/07)
'
' No filtrar el / ya que se usa para niveles de configuración       (01/Ago/07)
'
' Revisado para publicar en mi sitio (como revisión actualizada)    (12/Ene/08)
'
' ©Guillermo 'guille' Som, 2005-2008
'------------------------------------------------------------------------------
Option Explicit On 
Option Strict On

Imports Microsoft.VisualBasic
Imports System

Imports System.Collections
Imports System.Collections.Generic
Imports System.Configuration
Imports System.Xml
Imports System.IO

Namespace elGuille.info.Util
    Public Class ConfigXml

        '----------------------------------------------------------------------
        ' Los campos y métodos privados
        '----------------------------------------------------------------------
        Private mGuardarAlAsignar As Boolean = True
        Private Const configuration As String = "configuration/"
        Private ficConfig As String = ""
        Private configXml As New XmlDocument
        ' Los caracteres no permitidos en los nombres               (15/Ene/07)
        ' Se sustituirán por un guión bajo
        Private noPermitidos() As Char = " !|@#$%&()=?¿¡*[]{};.,:<>ç'ºª\-+".ToCharArray

        ' Para hacer las pruebas del tiempo empleado
        'Private mTest As New System.Diagnostics.Stopwatch
        'Private mt1, mt2 As TimeSpan
        '
        ' Mejor usar constantes                                 (15/Ene/07)
        ' y que estén al principio del fichero para tenerlas a mano
        Const revDate As String = "Sat, 12 Jan 2008 18:31:52 GMT"
        Const cfgInfo As String = "Generado con ConfigXml para Visual Basic 2008"
        Const copyGuille As String = "©Guillermo 'guille' Som, 2005-2008"


        ''' <summary>
        ''' Indica si se se guardarán los datos cuando se añadan nuevos.
        ''' </summary>
        ''' <value>
        ''' Indica si se se guardarán los datos cuando se añadan nuevos.
        ''' </value>
        ''' <returns>
        ''' Un valor verdadero o falso según el valor de la propiedad
        ''' </returns>
        ''' <remarks>21/Feb/06</remarks>
        Public Property GuardarAlAsignar() As Boolean
            Get
                Return mGuardarAlAsignar
            End Get
            Set(ByVal value As Boolean)
                mGuardarAlAsignar = value
            End Set
        End Property

        ''' <summary>
        ''' Obtiene un valor de tipo cadena de la sección y clave indicadas.
        ''' </summary>
        ''' <param name="seccion">
        ''' La sección de la que queremos obtener el valor
        ''' </param>
        ''' <param name="clave">
        ''' La clave de la que queremos recuperar el valor
        ''' </param>
        ''' <returns>
        ''' Un valor de tipo cadena con el valor de la sección y clave indicadas
        ''' </returns>
        ''' <remarks>
        ''' Existe otra sobrecarga para indicar un valor predeterminado.
        ''' Tanbién hay otras dos sobrecargas para valores enteros y boolean.
        ''' </remarks>
        Public Function GetValue(ByVal seccion As String, ByVal clave As String) As String
            Return GetValue(seccion, clave, "")
        End Function

        ''' <summary>
        ''' Obtiene un valor de tipo cadena de la sección y clave indicadas.
        ''' </summary>
        ''' <param name="seccion">
        ''' La sección de la que queremos obtener el valor
        ''' </param>
        ''' <param name="clave">
        ''' La clave de la que queremos recuperar el valor
        ''' </param>
        ''' <param name="predeterminado">
        ''' El valor predeterminado para cuando no exista.
        ''' </param>
        ''' <returns>
        ''' Un valor de tipo cadena con el valor de la sección y clave indicadas
        ''' </returns>
        ''' <remarks></remarks>
        Public Function GetValue(ByVal seccion As String, _
                                 ByVal clave As String, _
                                 ByVal predeterminado As String) As String
            Return cfgGetValue(seccion, clave, predeterminado)
        End Function

        ''' <summary>
        ''' Obtiene un valor de tipo entero de la sección y clave indicadas.
        ''' </summary>
        ''' <param name="seccion">
        ''' La sección de la que queremos obtener el valor
        ''' </param>
        ''' <param name="clave">
        ''' La clave de la que queremos recuperar el valor
        ''' </param>
        ''' <param name="predeterminado">
        ''' El valor predeterminado para cuando no exista.
        ''' </param>
        ''' <returns>
        ''' Un valor de tipo entero con el valor de la sección y clave indicadas
        ''' </returns>
        ''' <remarks></remarks>
        Public Function GetValue(ByVal seccion As String, _
                                 ByVal clave As String, _
                                 ByVal predeterminado As Integer) As Integer
            Return CInt(cfgGetValue(seccion, clave, predeterminado.ToString))
        End Function

        ''' <summary>
        ''' Obtiene un valor de tipo boolean de la sección y clave indicadas.
        ''' </summary>
        ''' <param name="seccion">
        ''' La sección de la que queremos obtener el valor
        ''' </param>
        ''' <param name="clave">
        ''' La clave de la que queremos recuperar el valor
        ''' </param>
        ''' <param name="predeterminado">
        ''' El valor predeterminado para cuando no exista.
        ''' </param>
        ''' <returns>
        ''' Un valor de tipo boolean con el valor de la sección y clave indicadas
        ''' </returns>
        ''' <remarks>
        ''' Internamente el valor se guarda con un cero para False y uno para True
        ''' </remarks>
        Public Function GetValue(ByVal seccion As String, _
                                 ByVal clave As String, _
                                 ByVal predeterminado As Boolean) As Boolean
            Dim def As String = "0"
            If predeterminado Then def = "1"
            def = cfgGetValue(seccion, clave, def)
            If def = "1" Then
                Return True
            Else
                Return False
            End If
        End Function

        ''' <summary>
        ''' Asignar un valor de tipo cadena en la sección y clave indicadas.
        ''' </summary>
        ''' <param name="seccion">
        ''' La sección de la que queremos obtener el valor
        ''' </param>
        ''' <param name="clave">
        ''' La clave de la que queremos recuperar el valor</param>
        ''' <param name="valor">
        ''' El valor a asignar</param>
        ''' <remarks>
        ''' El valor se guardar como un elemento de la sección indicada.
        ''' <seealso cref="SetKeyValue" />
        ''' </remarks>
        Public Sub SetValue(ByVal seccion As String, ByVal clave As String, ByVal valor As String)
            cfgSetValue(seccion, clave, valor)
        End Sub

        ''' <summary>
        ''' Asignar un valor de tipo entero en la sección y clave indicadas.
        ''' </summary>
        ''' <param name="seccion">
        ''' La sección de la que queremos obtener el valor</param>
        ''' <param name="clave">
        ''' La clave de la que queremos recuperar el valor</param>
        ''' <param name="valor">
        ''' El valor a asignar</param>
        ''' <remarks>
        ''' El valor se guardar como un elemento de la sección indicada.
        ''' El valor siempre se guarda como un valor de cadena.
        ''' <seealso cref="SetKeyValue" />
        ''' </remarks>
        Public Sub SetValue(ByVal seccion As String, ByVal clave As String, ByVal valor As Integer)
            cfgSetValue(seccion, clave, valor.ToString)
        End Sub

        ''' <summary>
        ''' Asignar un valor de tipo boolean en la sección y clave indicadas.
        ''' </summary>
        ''' <param name="seccion">
        ''' La sección de la que queremos obtener el valor</param>
        ''' <param name="clave">
        ''' La clave de la que queremos recuperar el valor</param>
        ''' <param name="valor">
        ''' El valor a asignar</param>
        ''' <remarks>
        ''' El valor se guardar como un elemento de la sección indicada.
        ''' El valor siempre se guarda como un valor de cadena, siendo un 1 para True y 0 para False.
        ''' <seealso cref="SetKeyValue" />
        ''' </remarks>
        Public Sub SetValue(ByVal seccion As String, ByVal clave As String, ByVal valor As Boolean)
            If valor Then
                cfgSetValue(seccion, clave, "1")
            Else
                cfgSetValue(seccion, clave, "0")
            End If
        End Sub

        ''' <summary>
        ''' Asigna un valor de tipo cadena en la sección y clave indicadas.
        ''' </summary>
        ''' <param name="seccion">
        ''' La sección de la que queremos obtener el valor</param>
        ''' <param name="clave">
        ''' La clave de la que queremos recuperar el valor</param>
        ''' <param name="valor">
        ''' El valor a asignar</param>
        ''' <remarks>
        ''' El valor se guarda como un atributo de la sección indicada.
        ''' La clave se guarda con el atributo key y el valor con el atributo value.
        ''' <seealso cref="SetValue" />
        ''' </remarks>
        Public Sub SetKeyValue(ByVal seccion As String, ByVal clave As String, ByVal valor As String)
            cfgSetKeyValue(seccion, clave, valor)
        End Sub

        ''' <summary>
        ''' Asigna un valor de tipo entero en la sección y clave indicadas.
        ''' </summary>
        ''' <param name="seccion">
        ''' La sección de la que queremos obtener el valor</param>
        ''' <param name="clave">
        ''' La clave de la que queremos recuperar el valor</param>
        ''' <param name="valor">
        ''' El valor a asignar</param>
        ''' <remarks>
        ''' El valor se guarda como un atributo de la sección indicada.
        ''' La clave se guarda con el atributo key y el valor con el atributo value.
        ''' El valor siempre se guarda como un valor de cadena.
        ''' <seealso cref="SetValue" />
        ''' </remarks>
        Public Sub SetKeyValue(ByVal seccion As String, ByVal clave As String, ByVal valor As Integer)
            cfgSetKeyValue(seccion, clave, valor.ToString)
        End Sub

        ''' <summary>
        ''' Asigna un valor de tipo boolean en la sección y clave indicadas.
        ''' </summary>
        ''' <param name="seccion">
        ''' La sección de la que queremos obtener el valor</param>
        ''' <param name="clave">
        ''' La clave de la que queremos recuperar el valor</param>
        ''' <param name="valor">
        ''' El valor a asignar</param>
        ''' <remarks>
        ''' El valor se guarda como un atributo de la sección indicada.
        ''' La clave se guarda con el atributo key y el valor con el atributo value.
        ''' El valor siempre se guarda como un valor de cadena, siendo un 1 para True y 0 para False.
        ''' <seealso cref="SetValue" />
        ''' </remarks>
        Public Sub SetKeyValue(ByVal seccion As String, _
                               ByVal clave As String, _
                               ByVal valor As Boolean)
            If valor Then
                cfgSetKeyValue(seccion, clave, "1")
            Else
                cfgSetKeyValue(seccion, clave, "0")
            End If
        End Sub

        ''' <summary>
        ''' Elimina la sección indicada, aunque en realidad la deja vacía.
        ''' </summary>
        ''' <param name="seccion">
        ''' La sección a eliminar.</param>
        ''' <remarks></remarks>
        Public Sub RemoveSection(ByVal seccion As String)
            Dim n As XmlNode
            ' Filtar la sección para evitar errores                 (15/Ene/07)
            seccion = filtrarNombre(seccion)

            n = configXml.SelectSingleNode(configuration & seccion)
            If Not n Is Nothing Then
                n.RemoveAll()
                ' Si se ha indicado que se guarde al asignar        (21/Feb/06)
                If mGuardarAlAsignar Then
                    Me.Save()
                End If
            End If
        End Sub

        ''' <summary>
        ''' Función de apoyo para filtrar los caracteres no permitidos
        ''' </summary>
        ''' <param name="nombre">
        ''' El nombre a filtrar</param>
        ''' <returns>
        ''' El nombre filtrado</returns>
        ''' <remarks>
        ''' Usar esta función internamente para que las secciones y claves
        ''' no incluyan los caracteres indicados en la constante noPermitidos
        ''' </remarks>
        Private Function filtrarNombre(ByVal nombre As String) As String
            ' Solo repetir el bucle si hay caracteres no permitidos
            ' Esto es más rápido si no tiene caracteres "raros",
            ' en caso de que los tenga, será más lento, pero...
            ' se supone que no debe tener caracteres no admitidos.
            'mTest.Reset()
            'mTest.Start()
            If nombre.IndexOfAny(noPermitidos) = -1 Then
                'mt1 = mTest.Elapsed
                Return nombre
            End If
            'mTest.Reset()
            'mTest.Start()
            Dim sb As New System.Text.StringBuilder(nombre)
            For Each c As Char In noPermitidos '.ToCharArray
                sb.Replace(c, "_"c)
            Next
            'mt2 = mTest.Elapsed
            Return sb.ToString
        End Function

        ''' <summary>
        ''' Eliminar la clave indicada
        ''' </summary>
        ''' <param name="seccion">
        ''' La sección en la que está la clave a eliminar
        ''' </param>
        ''' <param name="clave">
        ''' La clave a eliminar
        ''' </param>
        ''' <returns>
        ''' Devuelve True si se borró, en otro caso, devuelve False
        ''' </returns>
        ''' <remarks>
        ''' 15/Ene/07
        ''' Los valores al estilo de appSettings no se borran
        ''' </remarks>
        Public Function RemoveKey(ByVal seccion As String, _
                                  ByVal clave As String) As Boolean
            Dim n As XmlNode
            '
            ' Filtrar los caracteres no válidos
            ' en principio solo comprobamos el espacio
            'seccion = seccion.Replace(" ", "_")
            'clave = clave.Replace(" ", "_")
            seccion = filtrarNombre(seccion)
            clave = filtrarNombre(clave)
            '
            ' Primero comprobar si están el formato de appSettings: <add key = clave value = valor />
            n = configXml.SelectSingleNode(configuration & seccion & _
                                           "/add[@key=""" & clave & """]")
            If n IsNot Nothing Then
                ' Por ahora no se puede eliminar estas claves
                'n.Attributes.RemoveAll()
                Return False
            End If
            '
            ' Después se comprueba si está en el formato <Seccion clave = valor>
            n = configXml.SelectSingleNode(configuration & seccion)
            If n IsNot Nothing Then
                Dim a As XmlAttribute = n.Attributes(clave)
                If a IsNot Nothing Then
                    Dim b As XmlAttribute
                    b = n.Attributes.Remove(a)
                    If b Is Nothing Then
                        Return False
                    Else
                        ' Si en la clave no quedan claves ni atributos,
                        ' borrarla para que no se quede vacía
                        If n.HasChildNodes = False _
                        AndAlso (n.Attributes IsNot Nothing _
                                 AndAlso n.Attributes.Count = 0) Then
                            RemoveKey(seccion, n.Name)
                        End If
                        ' Si se ha indicado que se guarde al asignar
                        If mGuardarAlAsignar Then
                            Me.Save()
                        End If
                        Return True
                    End If
                End If
            End If
            '
            ' Por último se comprueba si es un elemento de seccion:
            '   <seccion><clave>valor</clave></seccion>
            ' Detectar los posibles errores...                      (15/Ene/07)
            Try
                n = configXml.SelectSingleNode(configuration & seccion & "/" & clave)
            Catch ex As Exception
                n = Nothing
            End Try
            'n = configXml.SelectSingleNode(configuration & seccion & "/" & clave)
            If n IsNot Nothing Then
                Dim n1 As XmlNode
                n1 = n.ParentNode.RemoveChild(n)
                If n1 Is Nothing Then
                    Return False
                Else
                    ' Eliminar la clave si no tiene otras claves ni atributos
                    n1 = configXml.SelectSingleNode(configuration & seccion)
                    If n1.HasChildNodes = False _
                    AndAlso (n1.Attributes IsNot Nothing _
                             AndAlso n1.Attributes.Count = 0) Then
                        n1.ParentNode.RemoveChild(n1)
                    End If
                    ' Si se ha indicado que se guarde al asignar    (15/Ene/07)
                    If mGuardarAlAsignar Then
                        Me.Save()
                    End If
                    Return True
                End If
            End If
            '
            Return False
        End Function

        ''' <summary>
        ''' Guardar el fichero de configuración.
        ''' </summary>
        ''' <remarks>
        ''' Si no se llama a este método, no se guardará de forma permanente.
        ''' Para guardar automáticamente al asignar,
        ''' asignar un valor verdadero a la propiedad 
        ''' <see cref="GuardarAlAsignar">GuardarAlAsignar</see>
        ''' </remarks>
        Public Sub Save()
            configXml.Save(ficConfig)
        End Sub

        ''' <summary>
        ''' Lee el fichero de configuración.
        ''' </summary>
        ''' <remarks>
        ''' Si no existe, se crea uno nuevo con los valores predeterminados.
        ''' </remarks>
        Public Sub Read()
            Dim fic As String = ficConfig

            If File.Exists(fic) Then
                configXml.Load(fic)
                ' Actualizar los datos de la información de esta clase
                Dim b As Boolean = mGuardarAlAsignar
                mGuardarAlAsignar = False
                Me.SetValue("configXml_Info", "info", cfgInfo)
                Me.SetValue("configXml_Info", "revision", revDate)
                Me.SetValue("configXml_Info", "formatoUTF8", _
                            "El formato de este fichero debe ser UTF-8")
                mGuardarAlAsignar = b
                Me.Save()
            Else
                ' Crear el XML de configuración con la sección General
                ' Aunque no se añadan retornos de carro, al guardarse se añaden y se indenta.
                Dim sb As New System.Text.StringBuilder
                sb.Append("<?xml version=""1.0"" encoding=""utf-8"" ?>")
                sb.Append("<configuration>")
                ' Por si es un fichero appSetting
                sb.Append("<configSections>")
                sb.Append("<section name=""General"" " & _
                          "type=""System.Configuration.DictionarySectionHandler"" />")
                sb.Append("</configSections>")
                sb.Append("<General>")
                sb.Append("<!-- Los valores irán dentro del elemento indicado por la clave -->")
                sb.Append("<!-- Aunque también se podrán indicar como pares key / value -->")
                sb.AppendFormat("<add key=""Revisión"" value=""{0}"" />", revDate)
                sb.Append("<!-- La clase siempre los añade como un elemento -->")
                sb.AppendFormat("<Copyright>{0}</Copyright>", copyGuille)
                sb.Append("</General>")
                ' Pero queda más "bonico" con los cambios de línea... en fin... cosas mías...
                sb.AppendFormat("<configXml_Info>{0}", vbCrLf)
                sb.AppendFormat("<info>{0}</info>{1}", cfgInfo, vbCrLf)
                sb.AppendFormat("<copyright>{0}</copyright>{1}", copyGuille, vbCrLf)
                sb.AppendFormat("<revision>{0}</revision>{1}", revDate, vbCrLf)
                sb.AppendFormat("<formatoUTF8>El formato de este fichero debe ser UTF-8" & _
                                "</formatoUTF8>{0}", vbCrLf)
                sb.AppendFormat("</configXml_Info>{0}", vbCrLf)
                '
                sb.Append("</configuration>")
                ' Asignamos la cadena al objeto
                configXml.LoadXml(sb.ToString)
                '
                ' Guardamos el contenido de configXml y creamos el fichero
                configXml.Save(ficConfig)
            End If
        End Sub

        ''' <summary>
        ''' El nombre del fichero de configuración.
        ''' </summary>
        ''' <value>
        ''' El path completo con el nombre del fichero de configuración.</value>
        ''' <returns>
        ''' Una cadena con el fichero de configuración.</returns>
        ''' <remarks>
        ''' El nombre del fichero se debe indicar en el constructor.
        ''' </remarks>
        Public Property FileName() As String
            Get
                Return ficConfig
            End Get
            Set(ByVal value As String)
                ' Al asignarlo, NO leemos el contenido del fichero
                ficConfig = value
                'LeerFile()
            End Set
        End Property

        ''' <summary>
        ''' Constructor en el que indicamos el nombre del fichero de configuración.
        ''' </summary>
        ''' <param name="fic">
        ''' El fichero a usar para guardar los datos de configuración.
        ''' </param>
        ''' <remarks>
        ''' Si no existe, se creará.
        ''' Al usar este constructor, por defecto se guardarán los valores al asignarlos.
        ''' </remarks>
        Public Sub New(ByVal fic As String)
            ficConfig = fic
            ' Por defecto se guarda al asignar los valores          (21/Feb/06)
            mGuardarAlAsignar = True
            Read()
        End Sub


        ''' <summary>
        ''' Constructor en el que indicamos el nombre del fichero de configuración
        ''' y si guardamos o no automáticamente.
        ''' </summary>
        ''' <param name="fic">
        ''' El fichero a usar para guardar los datos de configuración.</param>
        ''' <param name="guardarAlAsignar">
        ''' Un valor verdadero o falso para indicar
        ''' si se guardan los datos automáticamente al asignarlos.</param>
        ''' <remarks>21/Feb/06</remarks>
        Public Sub New(ByVal fic As String, ByVal guardarAlAsignar As Boolean)
            ficConfig = fic
            mGuardarAlAsignar = guardarAlAsignar
            Read()
        End Sub

        ''' <summary>
        ''' Devuelve una colección de tipo List con las secciones del fichero de configuración.
        ''' </summary>
        ''' <returns>
        ''' Una colección de tipo List(Of String) con las secciones del fichero de configuración.
        ''' </returns>
        ''' <remarks>
        ''' 21/Feb/06
        ''' Este método solo se puede usar en la .NET 2.0 o superior.
        ''' </remarks>
        Public Function Secciones() As List(Of String)
            Dim d As New List(Of String)
            Dim root As XmlNode
            Dim s As String = "configuration"
            root = configXml.SelectSingleNode(s)
            If root IsNot Nothing Then
                For Each n As XmlNode In root.ChildNodes
                    d.Add(n.Name)
                Next
            End If
            Return d
        End Function

        ''' <summary>
        ''' Devuelve una colección de tipo Dictionary con las claves y valores de la sección indicada.
        ''' </summary>
        ''' <param name="seccion">
        ''' La sección de la que queremos obtener las claves y valores.
        ''' </param>
        ''' <returns>
        ''' Una colección de tipo Dictionary(Of String, String) con las claves y valores.
        ''' </returns>
        ''' <remarks>
        ''' 21/Feb/06
        ''' Este método solo se puede usar en la .NET 2.0 o superior.
        ''' 15/Ene/07: También se devuelven los valores internos:
        ''' <![CDATA[ <Prueba2 Uno="Valor de uno" /> ]]>
        ''' En este caso, Prueba2 es una sección y Uno es una clave.
        ''' 15/Ene/07: También lee los pares valor/clave, por ejemplo:
        ''' <![CDATA[ <section name="General" type="System.Configuration.DictionarySectionHandler" /> ]]>
        ''' <![CDATA[ <add key="Revisión" value="Tue, 21 Feb 2006 19:45:00 GMT" /> ]]>
        ''' Antes solo devolvía section en el primer caso y add en el segundo,
        ''' ahora devuelve como clave el contenido de name/key y como valor type/value
        ''' respectivamente.
        ''' Nota sobre los comentarios insertados en el fichero de configuración:
        ''' Las claves #comment se devuelven numeradas, por tanto el valor devuelto
        ''' por esta colección no será el nombre real de ese nombre.
        ''' </remarks>
        Public Function Claves(ByVal seccion As String) As Dictionary(Of String, String)
            Dim d As New Dictionary(Of String, String)
            Dim root As XmlNode
            ' Para permitir más de un comentario
            Dim nComment As Integer = 0
            Dim sName As String

            seccion = filtrarNombre(seccion)

            root = configXml.SelectSingleNode(configuration & seccion)
            If root IsNot Nothing Then
                For Each n As XmlNode In root.ChildNodes
                    ' Si no queremos los comentarios                (15/Ene/07)
                    ' como parte de la colección de claves, dejar el Continue For
                    If n.Name = "#comment" Then
                        ' Si queremos tener todos los comentarios
                        nComment += 1
                        sName = n.Name & nComment.ToString("0000")
                    Else
                        sName = n.Name
                    End If
                    If d.ContainsKey(sName) = False Then
                        ' Si el valor es una cadena vacía,          (15/Ene/07)
                        ' es que están como atributos
                        If String.IsNullOrEmpty(n.InnerText) = False Then
                            d.Add(sName, n.InnerText)
                        Else
                            If n.Attributes IsNot Nothing AndAlso n.Attributes.Count = 2 Then
                                ' Deben existir dos atributos,
                                ' el primero es la clave y el segundo el valor
                                d.Add(n.Attributes(0).Value, n.Attributes(1).Value)
                            End If
                        End If
                    End If
                Next
                'TODO: 15/Ene/07
                ' En este caso, se debería asignar mediante SetKeyValue
                If root.Attributes IsNot Nothing AndAlso root.Attributes.Count > 0 Then
                    For Each a As XmlAttribute In root.Attributes
                        If d.ContainsKey(a.Name) = False Then
                            d.Add(a.Name, a.Value)
                        End If
                    Next
                End If
            End If
            Return d
        End Function

        '
        '----------------------------------------------------------------------
        ' Los métodos privados
        '----------------------------------------------------------------------
        '

        ' El método interno para guardar los valores
        ' Este método siempre guardará en el formato <seccion><clave>valor</clave></seccion>
        Private Sub cfgSetValue(ByVal seccion As String, _
                                ByVal clave As String, _
                                ByVal valor As String)
            Dim n As XmlNode

            ' Filtrar los caracteres no válidos
            seccion = filtrarNombre(seccion)
            clave = filtrarNombre(clave)

            ' Se comprueba si es un elemento de la sección:
            '   <seccion><clave>valor</clave></seccion>
            ' Detectar los posibles errores...                      (15/Ene/07)
            Try
                n = configXml.SelectSingleNode(configuration & seccion & "/" & clave)
            Catch ex As Exception
                n = Nothing
            End Try
            If n IsNot Nothing Then
                n.InnerText = valor
            Else
                Dim root As XmlNode
                Dim elem As XmlElement
                root = configXml.SelectSingleNode(configuration & seccion)
                If root Is Nothing Then
                    ' Si no existe el elemento principal,
                    ' lo añadimos a <configuration>
                    elem = configXml.CreateElement(seccion)
                    configXml.DocumentElement.AppendChild(elem)
                    root = configXml.SelectSingleNode(configuration & seccion)
                End If
                If root IsNot Nothing Then
                    ' Crear el elemento
                    elem = configXml.CreateElement(clave)
                    elem.InnerText = valor
                    ' Añadirlo al nodo indicado
                    root.AppendChild(elem)
                End If
            End If

            ' Si se debe guardar al asignar                         (21/Feb/06)
            If mGuardarAlAsignar Then
                Me.Save()
            End If
        End Sub

        ' Asigna un atributo a una sección
        ' Por ejemplo: <Seccion clave=valor>...</Seccion>
        ' También se usará para el formato de appSettings: <add key=clave value=valor />
        '   Aunque en este caso, debe existir el elemento a asignar.
        Private Sub cfgSetKeyValue(ByVal seccion As String, _
                                   ByVal clave As String, _
                                   ByVal valor As String)
            Dim n As XmlNode

            ' Filtrar los caracteres no válidos
            seccion = filtrarNombre(seccion)
            clave = filtrarNombre(clave)

            n = configXml.SelectSingleNode(configuration & seccion & "/add[@key=""" & clave & """]")
            If n IsNot Nothing Then
                n.Attributes("value").InnerText = valor
            Else
                Dim root As XmlNode
                Dim elem As XmlElement
                root = configXml.SelectSingleNode(configuration & seccion)
                If root Is Nothing Then
                    ' Si no existe el elemento principal,
                    ' lo añadimos a <configuration>
                    elem = configXml.CreateElement(seccion)
                    configXml.DocumentElement.AppendChild(elem)
                    root = configXml.SelectSingleNode(configuration & seccion)
                End If
                If root IsNot Nothing Then
                    Dim a As XmlAttribute
                    a = TryCast(configXml.CreateNode(XmlNodeType.Attribute, clave, Nothing),  _
                                XmlAttribute)
                    If a IsNot Nothing Then
                        a.InnerText = valor
                        root.Attributes.Append(a)
                    End If
                End If
            End If

            ' Si se debe guardar al asignar                         (21/Feb/06)
            If mGuardarAlAsignar Then
                Me.Save()
            End If
        End Sub

        ' Devolver el valor de la clave indicada
        Private Function cfgGetValue(ByVal seccion As String, _
                                     ByVal clave As String, _
                                     ByVal valor As String) As String
            Dim n As XmlNode

            ' Filtrar los caracteres no válidos
            ' en principio solo comprobamos el espacio
            seccion = filtrarNombre(seccion)
            clave = filtrarNombre(clave)

            ' Primero comprobar si están el formato de appSettings: <add key = clave value = valor />
            n = configXml.SelectSingleNode(configuration & seccion & "/add[@key=""" & clave & """]")
            If n IsNot Nothing Then
                Return n.Attributes("value").InnerText
            End If

            ' Después se comprueba si está en el formato <Seccion clave = valor>
            n = configXml.SelectSingleNode(configuration & seccion)
            If n IsNot Nothing Then
                Dim a As XmlAttribute = n.Attributes(clave)
                If a IsNot Nothing Then
                    Return a.InnerText
                End If
            End If

            ' Por último se comprueba si es un elemento de seccion:
            '   <seccion><clave>valor</clave></seccion>
            n = configXml.SelectSingleNode(configuration & seccion & "/" & clave)
            If n IsNot Nothing Then
                Return n.InnerText
            End If

            ' Si no existe, se devuelve el valor predeterminado
            Return valor
        End Function
    End Class
End Namespace

 

Espero que te sea de utilidad.

Nos vemos.
Guillermo



 


Haz tu donativo a este sitio con PayPal
 

Busca en este sitio con Google
 
Google

La fecha/hora en el servidor es: 19/04/2024 9:47:19

La fecha actual GMT (UTC) es: 

©Guillermo 'guille' Som, 1996-2024