jueves, 26 de enero de 2017

Crear archivo XML dinámico con C#


Crear archivo XML dinámico con C#

(Articulo republicado 01/26/2017. Porque lo borre sin querer queriendo :) )

Hola, hoy publico mi segunda entrada de este blog. En algunas circunstancias, nos encontramos con la necesidad de crear un archivo XML el cual necesitamos que la información que contiene interactué de forma dinámica con alguna aplicación que tengamos. En mi caso, yo tenía que guardar información en una aplicación que no se conecta a una base de datos. Mi solución fue crear un archivo XML pero la información que este contenida, cambiaba dinámicamente con el funcionamiento del sistema. a continuación muestro como realizar eso.

Primero y a manera de anexo tengo dos funciones que utilizo. La primera solo crea una carpeta, si la creación es exitosa responde True, caso contrario responde False. Y además si la carpeta ya existe pues retorna True también:


   1:  public static bool CrearCarpetaXml(string Ruta)
   2:          {
   3:              bool Respuesta = false;
   4:              try
   5:              {
   6:                  if (Directory.Exists(Ruta))
   7:                  {
   8:                      Respuesta = true;
   9:                  }
  10:                  else
  11:                  {
  12:                      Directory.CreateDirectory(Ruta);
  13:                      Respuesta = true;
  14:                  }
  15:                  return Respuesta;
  16:              }
  17:              catch (Exception ex)
  18:              {
  19:                 //logger.Error("Error en CrearCarpetaXml, ClaseXml:" 
                        + ex.Message);
  20:                  return Respuesta;
  21:                 //No fue posible crear el directorio...
  22:              }
  23:   
  24:          }

La siguiente función crea el archivo XML que necesitamos, es necesario definir la estructura según las necesidades. Para este ejercicio, vamos a crear un archivo XML que contenga algunas ventas que se hagan en alguna aplicación. Vamos a tener un nodo principal que se va a llamar "Transacciones", este nodo va a tener dos nodos hijos del mismo nivel que son, "RespuestaExitosa", "RespuestaFallida". No sobra decir que el archivo se va a actualizar según el tipo de respuesta obtenida.


   1:  private static bool CrearXmlTransacciones()
   2:          {
   3:              bool rta = false;
   4:   
   5:              try
   6:              {
   7:                  XmlTextWriter EscribirRec = 
                       new XmlTextWriter("ArchivosXml/Transacciones.xml", 
                                          System.Text.Encoding.UTF8);
   8:   
   9:                  EscribirRec.Formatting = Formatting.Indented;
  10:                  EscribirRec.Indentation = 2;
  11:                  EscribirRec.WriteStartDocument(false);
  12:                  EscribirRec.WriteComment("Lista de Transacciones");
  13:   
  14:                  EscribirRec.WriteStartElement("Transacciones");
  15:                  EscribirRec.WriteStartElement("Respuestas");
  16:   
  17:                  EscribirRec.WriteStartElement("RespuestaExitosa");
  18:                  EscribirRec.WriteEndElement();
  19:   
  20:                  EscribirRec.WriteStartElement("RespuestaFallida");
  21:                  EscribirRec.WriteEndElement();
  22:   
  23:                  EscribirRec.WriteEndElement();
  24:                  EscribirRec.WriteEndElement();
  25:                  EscribirRec.WriteEndDocument();
  26:                  EscribirRec.Close();
  27:                  rta = true;
  28:              }
  29:              catch (Exception ex)
  30:              {
  31:                  rta = false;
  32:              }
  33:   
  34:              return rta;
  35:          }

Ya creado el archivo con la estructura que necesitamos, viene lo interesante, como hacer para modificar el contenido justo donde lo necesitamos. Para esto creamos otra función la cual va a buscar el nodo donde queremos ingresar información. Este es el código de la función, posteriormente lo explico.


   1:  public static bool NodoTransacciones(string CodRespuesta, string MensajeRespuesta, 
                                            string CodProceso, string Proveedor, 
                                            string Producto, string NombreProducto, 
                                            string Monto, string Usuario)
   2:          {
   3:              XmlDocument XmlDoc;
   4:              XmlNode Raiz;
   5:              XmlNode ident;
   6:              bool rta = false;
   7:   
   8:              try
   9:              {
  10:                   XmlDoc = new XmlDocument();
  11:                   XmlDoc.Load("ArchivosXml/Transacciones.xml");
  12:                   Raiz = XmlDoc.DocumentElement;
  13:                 
  14:   
  15:                  if (CodRespuesta == "Exitosa")
  16:                  {
  17:                      ident = Raiz.FirstChild.FirstChild; 
                           // las transacciones quedarán en las exitosas
  18:                  }
  19:                  else
  20:                  {
  21:                      ident = Raiz.FirstChild.FirstChild.NextSibling; 
                           // las transacciones quedarán en las fallidas
  22:                  }
  23:   
  24:                  XmlElement NuevaTransaccion = XmlDoc.CreateElement("Transaccion"); 
                       //Como vamos a llamar el nuevo nodo
  25:                  NuevaTransaccion.InnerXml = "<Nombre></Nombre><CodRespuesta></CodRespuesta><MensajeRespuesta></MensajeRespuesta><CodProceso></CodProceso>" +
  26:                      "<Proveedor></Proveedor><Producto></Producto><NombreProducto></NombreProducto><Monto></Monto><Usuario></Usuario>"; // Este es el contenido que va a tener el nuevo nodo
  27:   
  28:                  NuevaTransaccion.AppendChild(XmlDoc.CreateWhitespace("\r\n"));
  29:                  NuevaTransaccion["Nombre"].InnerText = "transaccion de prueba";
  30:                  NuevaTransaccion["CodRespuesta"].InnerText = CodRespuesta;
  31:                  NuevaTransaccion["MensajeRespuesta"].InnerText = MensajeRespuesta;
  32:                  NuevaTransaccion["CodProceso"].InnerText = CodProceso;
  33:                  NuevaTransaccion["Proveedor"].InnerText = Proveedor;
  34:                  NuevaTransaccion["Producto"].InnerText = Producto;
  35:                  NuevaTransaccion["NombreProducto"].InnerText = NombreProducto;
  36:                  NuevaTransaccion["Monto"].InnerText = Monto;
  37:                  NuevaTransaccion["Usuario"].InnerText = Usuario;
  38:                 
  39:                  ident.InsertAfter(NuevaTransaccion, ident.LastChild);
  40:                  XmlTextWriter EscribirRec = 
                       new XmlTextWriter("ArchivosXml/Transacciones.xml", 
                                          System.Text.Encoding.UTF8);
  41:                  XmlDoc.WriteTo(EscribirRec);
  42:                  EscribirRec.Close();
  43:                  rta = true;
  44:              }
  45:              catch (Exception ex)
  46:              {
  47:                  rta = false;
  48:                  //logger.Error("Error en NodoTransacciones, ClaseXml:" + ex.Message);
  49:              }
  50:              return rta;
  51:          }

Lo importante en esta rutina es ubicarnos en el nodo donde queremos ingresar nuevos nodos. Yo uso en este caso un objeto llamado Raiz para ubicarme como su nombre lo dice en el nodo raíz del documento XML. Y después según el resultado de la transacción me ubico en el nodo que quiero usando el objeto ident.


Las propiedades que usamos para ubicarnos en los nodos que queremos son :


FirstChild: Hace referencia al primer nodo hijo de donde nos ubiquemos. También es posible ubicarse en el último con LastChild. Y para ubicarnos en el siguiente usamos NextSibling, entonces si ponemos una instrucción como Raiz.FirstChild.NextSiblig, estamos hablando del segundo nodo hijo del elemento raíz que en este caso se llama Respuestas.


Creamos un objeto de tipo XMLElement de nombre NuevaTrasaccion y le especificamos lo que va a contener con la propiedad NuevaTransaccion.InnerText.

Por último vamos a ver de que manera vamos a insertar el nuevo nodo con la nueva información que tenemos. Si queremos que se inserten antes o después, de últimos o de primeros. Para esto usamos el objeto que teniamos antes ident y con la propiedad InsertAfter, o también IsertBefore. En los argumentos le decimos lo que vamos a insertar y le indicamos en donde (si fuera de primero iden.FirstChild, si fuera de último ident.LastChild). 

Aquí les muestro el archivo Xml Inicial, cuando apenas se crea:





Esta imagen muestra el XML con la nueva información.



Ya solo queda llamar los cuatro metodos explicados arriba según lo necesiten.


Esto es todo por el momento, espero que le sirva a alguien esto. intenté ser lo más claro posible. Cualquier duda o comentario adelante.

martes, 31 de mayo de 2011

Imprimir por el Puerto LPT1 desde VB.net


Hola, esta es mi primera entrada de mi blog la idea de este blog es que el código que yo vaya haciendo en el trabajo en que estoy actualmente y represente algún desafío, compartirlo con todos ustedes. Ojalá a alguien le sirva.

Estuve trabajando en una aplicación de escritorio para un supermercado en un país de américa, el problema que surgió fue al momento de hacer la impresión de un tiket donde quedaba registrada la compra que se había realizado. La impresora es una impresora POS de referencia Epson TM-U950, la cual es algo curiosa ya que maneja dos recibos, uno que se llama Receipt (recibo que se le entrega al cliente) y otro que se llama Journal (copia del recibo original, que queda en el almacén). Además tenía que enviar alguna instrucción para en la impresión para abrir un cajón de dinero que estaba conectado a la impresora.

La impresora no se instaló en el computador, es decir, no se instaló ningún Driver en el sistema operativo, por esta razón la impresión tendría que manejarse directamente con el puerto paralelo. Para esto realicé una función sencilla en vb.net la cual imprime un texto, manda el corte de papel y por último envía la instrucción para abrir el cajón de dinero.


Función en Vb.net para imprimir en una impresora dual. Se imprime en los dos rollos ya que el texto que se envía a imprimir contiene 80 caracteres 40 para el primer rollo y 40 para el segundo. Para asegurarnos que se envíen los 40 caracteres, hay una función llamada Espacios que recibe un string de cualquier longitud y devuelve una cadena de 40 caracteres de longitud. Es el siguiente código.


   1:  Public Sub RecargaICEDoble()
   2:          
   3:          Dim objFSO
   4:          Dim objStream
   5:          objFSO = CreateObject("Scripting.FileSystemObject")
   6:          objStream = objFSO.CreateTextFile("LPT1") 'Puerto al cual se envía la impresión
   7:   
   8:          Try
   9:              
  10:              objStream.Writeline(Chr(27) & Chr(99) & Chr(48) & Chr(3)) 'Le pedimos que imprima tanto en el rollo Receipt como en el Journal
  11:              objStream.Writeline(Chr(27) & Chr(122) & Chr(0)) 'Ponemos en Off la impresion paralela
  12:              Dim Texto As String = "Esta es una prueba"
  13:              Dim Texto1 As String = "esta linea es diferente"
  14:              Texto = Espacios(Texto)
  15:              Texto1 = Espacios(Texto1)
  16:              objStream.Writeline(Texto & Texto)
  17:              objStream.Writeline(Texto & "*******")
  18:              objStream.Writeline("") 'Espacio en blanco
  19:              objStream.Writeline("")
  20:              objStream.Writeline(Chr(27) & Chr(109)) ' este es un corte de ticket, no completo
  21:              objStream.Writeline(Chr(27) & "p" & Chr(&H0) & Chr(&H64) & Chr(&H64)) ' este abre el cajon del dinero
  22:   
  23:          Catch ex As Exception
  24:          
  25:          Finally
  26:   
  27:              objStream.Writeline(Chr(27) & Chr(64)) ' limpia Buffer de la impresora
  28:              objStream.Writeline(Chr(27) & Chr(60)) ' la deja en Posicion Stand BY
  29:             
  30:              objStream.Close()
  31:   
  32:              objFSO = Nothing
  33:              objStream = Nothing
  34:   
  35:   
  36:          End Try
  37:      End Sub

La Función para calcular los 40 caracteres de cada recibo es la siguiente:


   1:  ublic Function Espacios(ByVal dato As String) As String
   2:          Dim rta As String = dato
   3:          Try
   4:              Dim h As Long
   5:              h = 1
   6:              If Len(dato) >= 40 Then
   7:                  dato = Mid(dato, 1, 40)
   8:                  Return rta
   9:              End If
  10:              Do
  11:                  If Len(dato) < 40 Then
  12:                      dato = dato & " "
  13:                  End If
  14:                  If Len(dato) = 40 Then
  15:                      rta = dato
  16:                      Return rta
  17:                  End If
  18:                  h = h + 1
  19:              Loop
  20:   
  21:          Catch ex As Exception
  22:              Return rta
  23:          End Try
  24:      End Function

El Resultado de impresión es el siguiente:



Para imprimir en una impresora de solo un rollo usamos solo el texto que se vaya a imprimir una sola vez sin concatenarlo como se hizo para la doble.
Espero que les sirva. Hasta la proxima!!