viernes, 28 de febrero de 2020

Pasar un JSON desde una Base de datos a un fichero de texto plano con formato JSON


Antes de nada tenemos que tener nuestro JSON almacenado en una base de datos. En este caso en lugar de almacenar toda la cadena JSON en un campo, hemos optado por almacenar cada nodo en una fila de la base de datos, de tal forma que cada fila deberá saber quien es su nodo padre.

La tabla empleada es de este tipo.

JSON almacenado en una Base de Datos


Debemos tener un código para cada nodo y otro para saber quien es el nodo padre, en otra columna almacenaremos los nombres de los nodos, y sus valores si los tienen. Como extra hemos añadido si son campos mandatory, o es un array.

Este es un ejemplo de cómo quedarían los datos en la tabla para un JSON genérico de Elastic Search.


Leerlo  desde la Base de datos y cargarlo en un Datagrid es bastante sencillo.

Creamos una pantalla de mantenimiento del DataGrid de este estilo.

Mantenimiento de una tabla

Este sería el Form_Load

Imports System.IO
Imports System.Data.OleDb
Imports System.Windows.Forms
Imports System.Data.SqlClient

Dim bolPrimeraVez As Boolean

Private Sub frmMantenimientoJSON_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.grdResult.DataSource = bs

        txtNodo.MaxLength = 40
        DefinicionJSON()

        Dim ObjetosPermitidos As Dictionary(Of String, String)
        ObjetosPermitidos = ComprobarPermisos(Me.Name)
        btnModificar.Visible = IIf(ObjetosPermitidos.ContainsKey("btnModificar"), True, False)
        btnBaja.Visible = IIf(ObjetosPermitidos.ContainsKey("btnBaja"), True, False)
        btnAlta.Visible = IIf(ObjetosPermitidos.ContainsKey("btnAlta"), True, False)
    End Sub



Aqui es donde lee de BBDD y lo pasa a un DataViewGrid (El DataGrid de la pantalla se llama grdresult).

 Sub DefinicionJSON()

        '  Dim dA As New OleDb.OleDbDataAdapter
        Dim tb As DataTable
        Dim srSQL As StreamReader
        Dim strConsulta As String
        Dim cmdbuilder As OleDbCommandBuilder


        tb = New DataTable

        ''Repeticion si no es la primera vez es que se ha llamado desde el mantenimiento y antes de cargarse debe borrarse la grid
        If Not bolPrimeraVez Then
            ds.Tables("DefinicionJSON").Clear()
        End If
        ''***********************

        strStartupPath = My.Application.Info.DirectoryPath
        srSQL = New System.IO.StreamReader(strStartupPath & "\CargarEsquemaJSON.sql")
        strConsulta = srSQL.ReadToEnd
        cmdPD = New OleDb.OleDbCommand(strConsulta, cnxPD)
        dA.SelectCommand = cmdPD
        cmdbuilder = New OleDbCommandBuilder(dA)
        dA.Fill(ds, "DefinicionJSON")

        If Not bolPrimeraVez Then
            Exit Sub
        End If

        bolPrimeraVez = False

        dA.UpdateCommand = cmdbuilder.GetUpdateCommand()
        dA.DeleteCommand = cmdbuilder.GetDeleteCommand()
        dA.InsertCommand = cmdbuilder.GetInsertCommand()

        bs.DataSource = ds.Tables(Tabla)

        Me.txtNodo.DataBindings.Add(New Binding("Text", bs, "COD_NODO_JSO"))
        Me.TxtNombreNodo.DataBindings.Add(New Binding("Text", bs, "DES_NODE"))
        Me.TxtNodoPadre.DataBindings.Add(New Binding("Text", bs, "COD_NODO_PAR"))
        Me.CboMandatory.DataBindings.Add(New Binding("Text", bs, "XTI_MANDATOR"))
        Me.CboReadOnly.DataBindings.Add(New Binding("Text", bs, "XTI_READ_ONL"))
        Me.txtUsuAuditoria.DataBindings.Add(New Binding("Text", bs, "AUD_USUARIO"))
        Me.txtFechaAuditoria.DataBindings.Add(New Binding("Text", bs, "AUD_TIM"

        grdResult.Columns(0).MinimumWidth = 100
        grdResult.Columns(1).MinimumWidth = 100
        grdResult.Columns(2).MinimumWidth = 100
        grdResult.Columns(3).MinimumWidth = 30
        grdResult.Columns(4).MinimumWidth = 30
        grdResult.Columns(5).MinimumWidth = 100
        grdResult.Columns(6).MinimumWidth = 100

        grdResult.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill

        grdResult.Columns(0).HeaderText = "Cod. Nodo"
        grdResult.Columns(1).HeaderText = "Nombre Nodo"
        grdResult.Columns(2).HeaderText = "Cod. Nodo Padre"
        grdResult.Columns(3).HeaderText = "Mandatory"
        grdResult.Columns(4).HeaderText = "Sólo lectura"
        grdResult.Columns(5).HeaderText = "Usuario Auditoria"
        grdResult.Columns(6).HeaderText = "Fecha Auditoria"
        grdResult.Refresh()

    End Sub

La SQL vendrá en el proyecto como CargarEsquemaJSON.sql y será una SELECT de este estilo:

SELECT  COD_NODO_JSO, DES_NODE, COD_NODO_PAR, XTI_MANDATOR, XTI_READ_ONL, AUD_USUARIO, AUD_TIM, DES_VALUE,XTI_ARRAY  FROM PROPIETARIO.TJSO order by COD_NODO_JSO


Este sería el código completo del programa:

Imports System.IO
Imports System.Data.OleDb
Imports System.Windows.Forms
Imports System.Data.SqlClient

Public Class frmMantenimientoJSON
    Dim ds As New DataSet()

    Dim bs As BindingSource = New BindingSource()
    Dim dA As New OleDb.OleDbDataAdapter
    Dim drEdit As DataRowView
    Dim bolRefrescar As Boolean
    Dim bolPrimeraVez As Boolean = True
    Const Tabla = "DefinicionJSON"

    Enum Accion
        Alta = 1
        Baja = 2
        Modificacion = 3
    End Enum

    Dim TipoAccion As Accion

    Private Sub frmMantenimientoJSON_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.grdResult.DataSource = bs

        txtNodo.MaxLength = 40

        DefinicionJSON()

        Dim ObjetosPermitidos As Dictionary(Of String, String)
        ObjetosPermitidos = ComprobarPermisos(Me.Name)
        btnModificar.Visible = IIf(ObjetosPermitidos.ContainsKey("btnModificar"), True, False)
        btnBaja.Visible = IIf(ObjetosPermitidos.ContainsKey("btnBaja"), True, False)
        btnAlta.Visible = IIf(ObjetosPermitidos.ContainsKey("btnAlta"), True, False)



    End Sub

    Sub DefinicionJSON()

        Dim tb As DataTable
        Dim srSQL As StreamReader
        Dim strConsulta As String
        Dim cmdbuilder As OleDbCommandBuilder


        tb = New DataTable

        ''Repeticion si no es la primera vez es que se ha llamado desde el mantenimiento y antes de cargarse debe borrarse la grid
        If Not bolPrimeraVez Then
            ds.Tables("DefinicionJSON").Clear()
        End If
        ''***********************

        strStartupPath = My.Application.Info.DirectoryPath
        srSQL = New System.IO.StreamReader(strStartupPath & "\CargarEsquemaJSON.sql")
        strConsulta = srSQL.ReadToEnd
        cmdPD = New OleDb.OleDbCommand(strConsulta, cnxPD)
        dA.SelectCommand = cmdPD
        cmdbuilder = New OleDbCommandBuilder(dA)
        dA.Fill(ds, "DefinicionJSON")

        If Not bolPrimeraVez Then
            Exit Sub
        End If

        bolPrimeraVez = False

        dA.UpdateCommand = cmdbuilder.GetUpdateCommand()
        dA.DeleteCommand = cmdbuilder.GetDeleteCommand()
        dA.InsertCommand = cmdbuilder.GetInsertCommand()

        bs.DataSource = ds.Tables(Tabla)

        Me.txtNodo.DataBindings.Add(New Binding("Text", bs, "COD_NODO_JSO"))
        Me.TxtNombreNodo.DataBindings.Add(New Binding("Text", bs, "DES_NODE"))
        Me.TxtNodoPadre.DataBindings.Add(New Binding("Text", bs, "COD_NODO_PAR"))
        Me.CboMandatory.DataBindings.Add(New Binding("Text", bs, "XTI_MANDATOR"))
        Me.CboReadOnly.DataBindings.Add(New Binding("Text", bs, "XTI_READ_ONL"))
        Me.txtUsuAuditoria.DataBindings.Add(New Binding("Text", bs, "AUD_USUARIO"))
        Me.txtFechaAuditoria.DataBindings.Add(New Binding("Text", bs, "AUD_TIM"))


        grdResult.Columns(0).MinimumWidth = 100
        grdResult.Columns(1).MinimumWidth = 100
        grdResult.Columns(2).MinimumWidth = 100
        grdResult.Columns(3).MinimumWidth = 30
        grdResult.Columns(4).MinimumWidth = 30
        grdResult.Columns(5).MinimumWidth = 100
        grdResult.Columns(6).MinimumWidth = 100

        grdResult.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill

        grdResult.Columns(0).HeaderText = "Cod. Nodo"
        grdResult.Columns(1).HeaderText = "Nombre Nodo"
        grdResult.Columns(2).HeaderText = "Cod. Nodo Padre"
        grdResult.Columns(3).HeaderText = "Mandatory"
        grdResult.Columns(4).HeaderText = "Sólo lectura"
        grdResult.Columns(5).HeaderText = "Usuario Auditoria"
        grdResult.Columns(6).HeaderText = "Fecha Auditoria"
        grdResult.Refresh()

    End Sub



    Private Sub btnFiltro_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFiltro.Click
        Dim strFiltro As String = ""
        Dim vwDefinicionJSON As DataView

        If txtFiltroNodo.Text <> "" Then
            If Not strFiltro = "" Then
                strFiltro = strFiltro & " AND "
            End If
            strFiltro = strFiltro & "COD_NODO_JSO LIKE '%" & txtFiltroNodo.Text & "%'" ' Name LIKE '%jo%'"
        End If

        If txtFiltroNombreNodo.Text <> "" Then
            If Not strFiltro = "" Then
                strFiltro = strFiltro & " AND "
            End If
            strFiltro = strFiltro & "DES_NODE LIKE '%" & txtFiltroNombreNodo.Text & "%'" ' Name LIKE '%jo%'"
        End If

        If txtFiltroNodoPadre.Text <> "" Then
            If Not strFiltro = "" Then
                strFiltro = strFiltro & " AND "
            End If
            strFiltro = strFiltro & "COD_NODO_PAR LIKE '%" & txtFiltroNodoPadre.Text & "%'" ' Name LIKE '%jo%'"
        End If

        If Not ds.Tables("DefinicionJSON") Is Nothing Then
            vwDefinicionJSON = ds.Tables("DefinicionJSON").DefaultView
            vwDefinicionJSON.RowFilter = strFiltro
        End If
    End Sub

    Private Sub btnAlta_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAlta.Click
        TipoAccion = Accion.Alta

        grbDetalle.Enabled = True
        grbBuscar.Enabled = False
        drEdit = bs.AddNew()
        bs.MoveLast()
        txtUsuAuditoria.Text = Environment.UserName
        txtFechaAuditoria.Text = Now
        grdResult.Refresh()
    End Sub

    Private Sub btnBaja_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnBaja.Click
        Dim drv As DataRowView
        Dim b As Integer
        TipoAccion = Accion.Baja
        Try

            If MsgBox("¿Esta usted seguro que desea borrar este registro?", MsgBoxStyle.YesNo + MsgBoxStyle.Question, "Confirmación de Baja") = MsgBoxResult.Yes Then
                drv = bs.Current
                b = grdResult.CurrentRow.Index
                drv.Delete()
            End If
            dA.Update(ds, Tabla)
            grbDetalle.Enabled = False
            grdResult.Refresh()
        Catch ex As Exception
            If Mid(ex.Message, 1, 9) = "ORA-00001" Then
                MsgBox("El código de Nodo debe ser único revise los datos e intentelo de nuevo", MsgBoxStyle.Critical, "Error al actualizar los datos")
            End If
            If Mid(ex.Message, 1, 9) = "ORA-02292" Then
                MsgBox("No está permitido el borrado en cascada, asegurese que el nodo no tiene Sub-nodos antes de borrarlo", MsgBoxStyle.Critical, "Error al actualizar los datos")
            End If
            Recargar()
        End Try
    End Sub

    Private Sub btnModificar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnModificar.Click
        TipoAccion = Accion.Modificacion
        grbDetalle.Enabled = True
        grbBuscar.Enabled = False
        txtUsuAuditoria.Text = Environment.UserName
        txtFechaAuditoria.Text = Now
    End Sub

    Private Sub btnAceptar_Click(sender As Object, e As EventArgs) Handles btnAceptar.Click
        Dim drv As DataRowView
        Try
            drv = bs.Current
            bs.EndEdit()
            dA.Update(ds, Tabla)

            grbBuscar.Enabled = True
            grbDetalle.Enabled = False

            grdResult.Refresh()
            DefinicionJSON() 'refresca los cambios
            bolRefrescar = False
        Catch ex As Exception
            If Mid(ex.Message, 1, 9) = "ORA-00001" Then
                MsgBox("El código de nodo debe ser único revise los datos e intentelo de nuevo", MsgBoxStyle.Critical, "Error al actualizar los datos")
            End If
            bolRefrescar = True
        End Try
    End Sub
  

    Private Sub btnCancelar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancelar.Click
        bs.CancelEdit()
        If bolRefrescar Then
            Recargar()
        End If
        grbDetalle.Enabled = False
        grbBuscar.Enabled = True
    End Sub

    Sub Recargar()
        bolRefrescar = False
        ds.Tables(1).Clear()
        ds.Tables(0).Clear()
        DefinicionJSON()
        grdResult.Refresh()
    End Sub

    Private Sub txtColumna_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtNodo.TextChanged
        txtNodo.MaxLength = 8
    End Sub

    Sub AplicarFiltro()
        Dim strFiltro As String = ""
        Dim vwDefinicionJSON As DataView

        If txtFiltroNodo.Text <> "" Then
            If Not strFiltro = "" Then
                strFiltro = strFiltro & " AND "
            End If
            strFiltro = strFiltro & "COD_NODO_JSO LIKE '%" & txtFiltroNodo.Text & "%'" ' Name LIKE '%jo%'"
        End If

        If txtFiltroNombreNodo.Text <> "" Then
            If Not strFiltro = "" Then
                strFiltro = strFiltro & " AND "
            End If
            strFiltro = strFiltro & "DES_NODE LIKE '%" & txtFiltroNombreNodo.Text & "%'" ' Name LIKE '%jo%'"
        End If

        If txtFiltroNodoPadre.Text <> "" Then
            If Not strFiltro = "" Then
                strFiltro = strFiltro & " AND "
            End If
            strFiltro = strFiltro & "COD_NODO_PAR LIKE '%" & txtFiltroNodoPadre.Text & "%'" ' Name LIKE '%jo%'"
        End If

        If Not ds.Tables("DefinicionJSON") Is Nothing Then
            vwDefinicionJSON = ds.Tables("DefinicionJSON").DefaultView
            vwDefinicionJSON.RowFilter = strFiltro
        End If

    End Sub

    Private Sub txtFiltroNombre_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtFiltroNodo.TextChanged
        AplicarFiltro()
    End Sub

    Private Sub txtFiltroNombre_Validated(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtFiltroNodo.Validated
        ' AplicarFiltro()
    End Sub

    Private Sub txtFiltroDescripcion_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtFiltroNodoPadre.TextChanged
        AplicarFiltro()
    End Sub

    Private Sub cboFiltroAmbito_Validated(ByVal sender As Object, ByVal e As System.EventArgs)
        AplicarFiltro()
    End Sub

    Private Sub txtFiltroTipo_TextChanged(sender As Object, e As EventArgs) Handles txtFiltroNombreNodo.TextChanged
        AplicarFiltro()
    End Sub

  

    Private Sub grbFiltro_Enter(sender As Object, e As EventArgs) Handles grbFiltro.Enter

    End Sub

    Private Sub btnJSON_Click(sender As Object, e As EventArgs) Handles btnJSON.Click
        Dim d As New frmParseoJSON()  'envia los datos del grid al formulario hijo
        d.ShowDialog()
        d.WindowState = FormWindowState.Normal
    End Sub
End Class


viernes, 14 de febrero de 2020

Compilar paso a paso un proyecto de Visual Basic Script

Compilación avanzada de con Visual Studio

Hay veces que el código que ejecutamos no es el mismo que vemos en Visual Studio. Puede haber varias razones, como la utilización de parámetros internos, recompilaciones o cualquier cosa que nos haga ver una cosa y ejecute otra. Para depurar el código que realmente se está ejecutando en la máquina se puede utilizar el método descrito a continuación.

Ejecutamos el archivo .exe generado para nuestra aplicación, y en el momento que deseamos para la ejecución, abrimos Visual Studio y hacemos Depurar -> Asociar al Proceso (ctrl+ Alt + P) y elegimos el hilo de nuestro ejecutable (es el mismo método que se describe a continuación para Visual Basic Script)

Si el código que ejecuta es el mismo de nuestro VS lo mostrará en amarillo, si no es igual, mostrará por donde va, pero la línea no irá en amarillo, eso nos dará la pista de que lo que ejecuta no es lo mismo que tenemos escrito en el código.

Compilación de archivos de Visual Basic Script

Un archivo de Visual Basic Script no se puede compilar, hay que ir poniendo Msgbox para hacerse una idea de por donde va y lo que va haciendo, pero hay veces que la ejecución de un vbs llama a un proyecto de Visual Basic normal y este último si se puede compilar. Para ello necesitamos compilación remota. 


Desde el proyecto VB se ejecuta un procedimiento que es llamado a través de un archivo Vbs esto se hace con el código coloreado.

  Sub Main()
        ' System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = False
        AbrirLog()

         log = LogManager.GetLogger(System.Reflection.Assembly.GetExecutingAssembly().GetType())
        Try
            log4net.Config.XmlConfigurator.Configure()

            Dim i As Integer
            Dim strArg As String = ""
            For i = 1 To Environment.GetCommandLineArgs.Length - 1
                strArg = strArg & Environment.GetCommandLineArgs(i) & " "
            Next

            If strArg = "" Then
                strArg = "Generación del Modelo Físico"
            End If
            EscribirLog("Proceso: " & strArg & " - " & Now())

            PD = New PdCommon.Application
            PDStartTime = Now
            PD.InteractiveMode = InteractiveModeValue.im_Dialog

            LeerConfig()
            'Comprobamos que proceso se quiere realizar.
            If Environment.GetCommandLineArgs.GetLength(0) = 1 Then
                Dim d As New frmMain

                AbrirConexionPD()
                d.ShowDialog()
            End If

            i = 0
            For Each arg As String In Environment.GetCommandLineArgs()

                Select Case i
                    Case 1 'Argumento primero

                        Select Case arg.ToUpper
                            Case "EtiquetaVBs".ToUpper
                                MsgBox("comienza ejecucion VB")
                                ProcedimientoVB()
                                …
                                …

Para ello hacemos lo siguiente:

primero ejecutamos el  proyecto de VB en modo debug para generar el .exe; hecho esto ejecutamos de nuevo desde Visual Studio y vamos al archivo Vbs que contiene una llamada de este estilo al proyecto de VB.

Compilar paso a paso un proyecto de Visual Basic Script


dim EjecObj
Dim Cadena

Cadena = """C:\Proyectos\bin\x86\Debug\ADE.exe"" ""etiquetaVBs"""
set EjecObj = createobject("Wscript.shell")
EjecObj.Run(Cadena)

Hay que tener en cuenta que la ruta llamada debe coincidir con la ruta donde se ha alojado el archivo .exe al generarlo en modo Debug.

Al ejecutar el archivo Vbs que contiene esta líneas, llama al proyecto VB que se ejecuta hasta llegar al MsgBox.   

MsgBox("comienza ejecucion VB")

Al parar en este punto, vamos al proyecto de VB en visual studio y en el menu depurar elegimos asociar al proceso.

Asociar proceso VB


Y elegimos nuestro proyecto como proceso.

Asociar un proceso Visual Basic Script a otro de VB

Y pulsamos asociar, esto no hace aparentemente nada, debemos pulsar en interrumpir todo.

Pausar ejecución de un proceso

Entonces la línea de nuestro Msgbox se queda verde.

Comenzar ejecución de Proceso de Vbs

Ahora pulsamos F11 o F10 para comenzar con la depuración y nos sale el MsgBox.

Depurar un proceso VB Script

Pulsamos aceptar y la línea se pone en amarillo con lo que ya podemos comenzar con la depuración.

Depurar un proceso VB Script


sábado, 1 de febrero de 2020

Cargar y leer diccionarios en Visual Basic.net


Para muchas aplicaciones es interesante crear y administrar grupos de objetos relacionados. Existen dos formas de agrupar objetos: con matrices de objetos y con colecciones (diccionarios) de objetos.
Los diccionarios proporcionan una manera más flexible de trabajar con grupos de objetos. A diferencia de las matrices, el grupo de objetos con el que trabaja puede aumentar y reducirse de manera dinámica. Para algunos diccionarios, podemos asignar una clave a cualquier objeto que incluyamos en la colección y de este modo, recuperar rápidamente el objeto con la clave.

sábado, 18 de enero de 2020

Google App Script: Código común para varios objetos y versionado.


El objetivo de esta entrada consiste explicar cómo tocar el mínimo código imprescindible en diferentes objetos de Google Drive (por ejemplo varias Spreadsheet, Docs, etc conectadas a una plantilla común de código fuente), de modo que el código deberá ser el mismo para todos los objetos, y así el código asociado a cada objeto sea el mínimo posible y llame siempre a funciones globales. Además deberemos tener en cuenta la versión del código común.

Primero, sobre nuestro objeto de Google Drive pulsamos Herramientas -> Editor de secuencias de Comandos.

Desarrollar código con Google Script

sábado, 4 de enero de 2020

Instalar Keras y TensorFlow. Sistema de reconocimiento de imágenes

Keras y TensorFlow


Keras es una biblioteca de redes neuronales de alto nivel que sirve como una capa de abstracción fácil de usar sobre la biblioteca TensorFlow. 

Creamos un environment del mismo nombre en anaconda.

Anaconda navigator