Secciones de la página

xlx. tol


Declaraciones


Variables de control


Constantes


Funciones


Time oriented language


Árbol de ficheros

Funciones

Set XlxSetCtr()

Text XlxFromLblToEnd()

Text XlxFromTagToEnd()

Set XlxFromTagToAtrVal()

Set XlxSplitByTag()

Set XlxSplitByTagAtrVal()

Real Xlx7ZipExtract()

Real Xlx7ZipTest()

Real XlxIsExcelXlsx()

Text XlxReadText()

Set XlxReadTable()

Set XlxReadShared()

Set XlxReadTableShared()

Tol

Artículos del sitio

Presentación de Tol

Todos los programas

Simuladores visuales

Sitios que me gustan

Por categorías

Algoritmia

Búsqueda y ordenación

Computación fisiológica

Editorial y edición

Gráficos de datos

Herramientas y utilidades

Hipertexto

Informática forense

Lectura óptica de datos

Metaprogramación

No determinista

Ofimática

Recursión e iteración

Reglas y restricciones

Series y estadística









xlx.tol de Xlsx.Reader

Lectura basica de ficheros Excel Xlsx. Los Xlsx son ficheros comprimidos y se pueden abrir con WinZip o 7Zip. Este codigo usa 7Zip para extraer la hoja de datos requerida 1, 2, 3,... Por ejemplo, se puede extraer el contenido de la hoja 1 con el mandato: 7z.exe e excel.xlsx xl\worksheets\sheet1.xml -so > _temporal_.xml La hoja es un fichero Xml con los tags <sheetData> <row> y <v> (value). Por lo que puede convertirse en un conjunto de conjunto de textos. Este codigo no realiza especiales comprobaciones: a) ni de mayusculas ni minusculas en las etiquetas Xml, b) ni de celdas combinadas, c) omite las celdas vacias que no se guarden, por lo que el resultado puede no ser rectangular, d) tampoco extrae formulas, ni formatos y e) todos los campos los retorna en formato de texto, asi, por ejemplo, las fechas se retornan como un numero en formato de texto y f) dependiendo de XlxCpm retorna todos los textos compactados o no, de forma independiente a las directrices del tipo xml:space = preserve. A partir de este codigo pueden programarse lectores de Xlsx mas avanzados. El unico fichero temporal que usa no se borra para facilitar la validacion. Hay 2 tipos de funciones: a) la que retorna directamente los contenidos y b) la que si el contenido de la celda no es un valor sino es el indice a la tabla de shared strings realiza la busqueda en esa tabla y retorna los contenidos reales. Para entender el uso de la tabla de sharedStrings en Excel Xlsx puede consultarse el sitio web: http://www.sadev.co.za/content en reading-and-writing-excel-2007-or-excel-2010-c-series-index

Declaraciones

Variables de control

  • Real XlxCmp
    Si cierto compacta todos los textos siempre.
  • Real XlxTra
    Si cierto traduce de Xml a Ascii los & < y >.

Constantes

  • Text XlxChr
    Caracter separador que se espera unico.
  • Text XlxTmp
    Fichero temporal que se espera unico.
  • Text Xlx7zp
    Path al progama ejecutable 7 Zip.
  • Text XlxSha
    Atributo shared string con dobles comillas.
  • Set XlxRep
    Tabla de reemplazamientos Xml a Ascii.

Funciones

  • Set XlxSetCtr(Real newCmp, Real newTra)
    Memoriza los nuevos valores para los controles XlxCmp y XlxTra sobre la compactacion y traduccion de los textos leidos de ficheros Excel Xlsx, que se emplearan a partir de la llamada a esta funcion, esto es, actualiza los parametros de control. Retorna los valores anteriores por si se desean restaurar posteriormente.
  • Text XlxFromLblToEnd(Text txtXml, Text lblIni)
    Retorna todo el texto a la derecha de la primera ocurrencia de la etiqueta lblIni en txtXml. Si la etiqueta lblIni no aparece retorna el texto vacio.
  • Text XlxFromTagToEnd(Text txtXml, Text tagIni)
    Retorna todo el texto a la derecha de la primera ocurrencia del tag tagIni. Tiene en cuenta la forma de los tags Xml <tagIni . . .>. Es adecuada cuando no interesan los atributos del tag. Si tagIni no aparece o esta mal formado retorna el texto vacio.
  • Set XlxFromTagToAtrVal(Text txtXml, Text tagIni)
    Retorna un par con el contenido de los atributos del tag y el valor hasta el final, por ejemplo, <c a=1>valor a la derecha -> [a=1, valor a la derecha]. Es adecuada cuando si interesan los atributos del tag. Si tagIni no aparece o esta mal formado retorna textos vacios.
  • Set XlxSplitByTag(Text txtXml, Text tagBrk)
    Retorna el conjunto de todos los textos entre <tagBrk> y </tagBrk>. Es adecuada cuando no interesan los atributos del tag. XlxSplitByTag(a<v>1</v>b<v>2</v>c<v>3</v>d, v)-> [1,2,3] pero no los textos a b c d.
  • Set XlxSplitByTagAtrVal(Text txtXml, Text tagBrk)
    Retorna el conjunto de pares formados por (todos los atributos, valor del contenido) de un tag XML. Siendo: a) los atributos del tag <tagBrk...a1=1 a2=2...aN=n> y b) el texto entre <tagBrk...> y </tagBrk> el valor de su contenido. Es adecuada cuando si interesan los atributos del tag.
  • Real Xlx7ZipExtract(Text inpPth, Text sheIde, Text outPth)
    Retorna cierto si puede extraer la hoja numero sheIde del fichero Excel Xlsx de camino inpPth y guardarla en el fichero de salida de camino outPth. Para los casos sencillos sheIde puede ser un numero en forma de texto, por ejemplo si es un 2 se asume xl/worksheets/sheet2.xml. Si sheIde, no es un numero y empieza por xl, entonces se asume que se esta proporcionando el path completo de la hoja, por ejemplo, xl/externalLinks/externalLink1.xml, que en Excels dinamicos pueden contener la informacion que no contienen las hojas visibles.
  • Real Xlx7ZipTest(Text inpPth)
    Retorna cierto si el fichero inpPth tiene una estructura PK correcta.
  • Real XlxIsExcelXlsx(Text inpPth)
    Retorna cierto si inpPth tiene la extension y estructura PK correctas.
  • Text XlxReadText(Text inpPth, Text sheIde)
    Retorna el texto Xml del Excel Xlsx de camino inpPth de su hoja sheIde.
  • Set XlxReadTable(Text inpPth, Text sheIde)
    Retorna una tabla, como conjunto de filas de conjuntos de celdas, con el contenido en texto del Excel Xlsx de camino inpPth de su hoja sheIde. Se trata de una version simple que puede retornar tablas no extrictamente rectangulares si hay celdas sin contenido o celdas combinadas. En caso de error retorna el conjunto vacio. Usa un metodo simple retornando el contenido de las celdas sin tener en cuenta la posible existencia de shared strings.
  • Set XlxReadShared(Text inpPth)
    Retorna una lista como un conjunto lineal de los shared strings de un fichero Excel Xlsx. Esta lista de textos compartido se guarda en el Xml xl/sharedStrings.xml con el formato: <sst...> <si><t>Estos son los strings compartidos y</t></si> <si><t>enumerados del 0 al n</t></si> <si><t>aunque en tol del 1 al n+1</t></si> </sst> En caso de error esta funcion retorna el conjunto vacio.
  • Set XlxReadTableShared(Text inpPth, Text sheIde)
    Retorna una tabla, como conjunto de filas de conjuntos de celdas, con el contenido en texto del Excel Xlsx de camino inpPth de su hoja sheIde. Se trata de una version simple que puede retornar tablas no extrictamente rectangulares si hay celdas sin contenido o celdas combinadas. A diferencia de XlxReadTable() lee previamente la tabla de shared string y comprueba en cada celda si el contenido es el original o si es un indice a la tabla de textos compartidos. Estos Xml tienen el formato: <c r='A1'><v>Soy un contenido original pero la celda C1 no lo tiene</v></c> <c r='B1'><v>Lo marca el atributo t=s y hay que usar el indice 652</v></c> <c r='C1' t='s'><v>652</v></c> En caso de error retorna el conjunto vacio.

Variables de control

Real XlxCmp

//////////////////////////////////////////////////////////////////////////////
Real XlxCmp = TRUE;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Si cierto compacta todos los textos siempre.",
XlxCmp);
//////////////////////////////////////////////////////////////////////////////

Real XlxTra

//////////////////////////////////////////////////////////////////////////////
Real XlxTra = TRUE;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Si cierto traduce de Xml a Ascii los & < y >.",
XlxTra);
//////////////////////////////////////////////////////////////////////////////

Constantes

Text XlxChr

//////////////////////////////////////////////////////////////////////////////
Text XlxChr = Char(7);
//////////////////////////////////////////////////////////////////////////////
PutDescription("Caracter separador que se espera unico.",
XlxChr);
//////////////////////////////////////////////////////////////////////////////

Text XlxTmp

//////////////////////////////////////////////////////////////////////////////
Text XlxTmp = "tmp/_xlsx_.tmp";
//////////////////////////////////////////////////////////////////////////////
PutDescription("Fichero temporal que se espera unico.",
XlxTmp);
//////////////////////////////////////////////////////////////////////////////

Text Xlx7zp

//////////////////////////////////////////////////////////////////////////////
Text Xlx7zp = "bin/7zip/7z.exe";
//////////////////////////////////////////////////////////////////////////////
PutDescription("Path al progama ejecutable 7 Zip.",
Xlx7zp);
//////////////////////////////////////////////////////////////////////////////

Text XlxSha

//////////////////////////////////////////////////////////////////////////////
Text XlxSha = "t=\"s\""; 
//////////////////////////////////////////////////////////////////////////////
PutDescription("Atributo shared string con dobles comillas.",
XlxSha);
//////////////////////////////////////////////////////////////////////////////

Set XlxRep

//////////////////////////////////////////////////////////////////////////////
Set  XlxRep = [[ [["&amp;","&"]],
                 [["&lt",  "<"]],
                 [["&gt;", ">"]] ]];
//////////////////////////////////////////////////////////////////////////////
PutDescription("Tabla de reemplazamientos Xml a Ascii.",
XlxRep);
//////////////////////////////////////////////////////////////////////////////

Funciones

Set XlxSetCtr()

//////////////////////////////////////////////////////////////////////////////
Set  XlxSetCtr(Real newCmp, // Nuevo valor para el control de compactacion
               Real newTra) // Nuevo valor para el control de traduccion
//////////////////////////////////////////////////////////////////////////////
{
  Set  oldVal = SetOfText(Copy(XlxCmp), Copy(XlxTra)); // Valores actuales
  Text(XlxCmp:=Copy(newCmp)); // Memoriza la nueva compactacion
  Text(XlxTra:=Copy(newTra)); // Memoriza la nueva traduccion
  oldVal // Retorna los antiguos valores
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Memoriza los nuevos valores para los controles XlxCmp y XlxTra sobre 
la compactacion y traduccion de los textos leidos de ficheros Excel Xlsx,
que se emplearan a partir de la llamada a esta funcion, esto es, actualiza
los parametros de control.
Retorna los valores anteriores por si se desean restaurar posteriormente.",
XlxSetCtr);
//////////////////////////////////////////////////////////////////////////////

Text XlxFromLblToEnd()

//////////////////////////////////////////////////////////////////////////////
Text XlxFromLblToEnd(Text txtXml, // Original Xml text
                     Text lblIni) // Initial label
//////////////////////////////////////////////////////////////////////////////
{
  Text xml2Asc(Text xmlTxt) { ReplaceTable(xmlTxt, XlxRep) }; // Cambia & < >
  
  Real posIni = TextFind(txtXml, lblIni);
  If(LE(posIni,0), "",
  {
    Real posSub = posIni + TextLength(lblIni);
    Real posEnd = TextLength(txtXml);
    Text subTxt = Sub(txtXml,posSub,posEnd);
    Text subCmp = If(XlxCmp, Compact(subTxt), subTxt); // Compacta si procede
    Text subTra = If(XlxTra, xml2Asc(subCmp), subCmp); // Traduce si procede
    subTra
  })
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna todo el texto a la derecha de la primera ocurrencia de la etiqueta
lblIni en txtXml.
Si la etiqueta lblIni no aparece retorna el texto vacio.",
XlxFromLblToEnd);
//////////////////////////////////////////////////////////////////////////////

Text XlxFromTagToEnd()

//////////////////////////////////////////////////////////////////////////////
Text XlxFromTagToEnd(Text txtXml, // Original Xml text
                     Text tagIni) // Initial tag without < >
//////////////////////////////////////////////////////////////////////////////
{ XlxFromLblToEnd(XlxFromLblToEnd(txtXml, "<"+tagIni), ">") };
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna todo el texto a la derecha de la primera ocurrencia del tag tagIni.
Tiene en cuenta la forma de los tags Xml <tagIni . . .>.
Es adecuada cuando no interesan los atributos del tag.
Si tagIni no aparece o esta mal formado retorna el texto vacio.",
XlxFromTagToEnd);
//////////////////////////////////////////////////////////////////////////////

Set XlxFromTagToAtrVal()

//////////////////////////////////////////////////////////////////////////////
Set XlxFromTagToAtrVal(Text txtXml, // Original Xml text
                       Text tagIni) // Initial tag without < >
//////////////////////////////////////////////////////////////////////////////
{
  Text atrVal = XlxFromLblToEnd(txtXml, "<"+tagIni);
  Text atrTxt = Sub(atrVal, 1, TextFind(atrVal, ">")); // De > a la izquierda
  Text valTxt = XlxFromLblToEnd(atrVal, ">");          // De > a la derecha
  SetOfText(atrTxt, valTxt)
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna un par con el contenido de los atributos del tag y el valor hasta el
final, por ejemplo, <c a=1>valor a la derecha -> [a=1, valor a la derecha].
Es adecuada cuando si interesan los atributos del tag.
Si tagIni no aparece o esta mal formado retorna textos vacios.",
XlxFromTagToAtrVal);
//////////////////////////////////////////////////////////////////////////////

Set XlxSplitByTag()

//////////////////////////////////////////////////////////////////////////////
Set XlxSplitByTag(Text txtXml, // Original Xml text
                  Text tagBrk) // Tag for break, without < </ >
//////////////////////////////////////////////////////////////////////////////
{
  Set tokSet = Tokenizer(Replace(txtXml, "</"+tagBrk+">", XlxChr), XlxChr);
  For(1, Card(tokSet)-1, Text(Real posSet)
      { XlxFromTagToEnd(tokSet[posSet], tagBrk) })
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna el conjunto de todos los textos entre <tagBrk> y </tagBrk>.
Es adecuada cuando no interesan los atributos del tag.
  XlxSplitByTag(a<v>1</v>b<v>2</v>c<v>3</v>d, v)-> [1,2,3]
pero no los textos a b c d.",
XlxSplitByTag);
//////////////////////////////////////////////////////////////////////////////

Set XlxSplitByTagAtrVal()

//////////////////////////////////////////////////////////////////////////////
Set XlxSplitByTagAtrVal(Text txtXml, // Original Xml text
                        Text tagBrk) // Tag for break, without < </ >
//////////////////////////////////////////////////////////////////////////////
{
  Set tokSet = Tokenizer(Replace(txtXml, "</"+tagBrk+">", XlxChr), XlxChr);
  For(1, Card(tokSet)-1, Set(Real posSet)
      { XlxFromTagToAtrVal(tokSet[posSet], tagBrk) })
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna el conjunto de pares formados por (todos los atributos,
valor del contenido) de un tag XML.
Siendo:
a) los atributos del tag <tagBrk...a1=1 a2=2...aN=n> y
b) el texto entre <tagBrk...> y </tagBrk> el valor de su contenido.
Es adecuada cuando si interesan los atributos del tag.",
XlxSplitByTagAtrVal);
//////////////////////////////////////////////////////////////////////////////

Real Xlx7ZipExtract()

//////////////////////////////////////////////////////////////////////////////
Real Xlx7ZipExtract(Text inpPth, // Input path, the Xlsx Excel file path
                    Text sheIde, // Sheet number 1, 2,... or sheet path
                    Text outPth) // Output path, the Xml output file
//////////////////////////////////////////////////////////////////////////////
{
  Text xmlPth = If(TextBeginWith(sheIde, "xl"), sheIde, // Dan path completo
                "xl/worksheets/sheet"+sheIde+".xml");

  Text cmdTxt = Xlx7zp + " e " + Q(inpPth) + " " + xmlPth +  // Extrae de
                " -so > " + outPth;                          // Vuelca en
  Text cmdDos = W(cmdTxt);
  Text WriteLn(cmdDos);
  System(cmdDos)
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna cierto si puede extraer la hoja numero sheIde del fichero Excel Xlsx
de camino inpPth y guardarla en el fichero de salida de camino outPth.
Para los casos sencillos sheIde puede ser un numero en forma de texto,
por ejemplo si es un 2 se asume xl/worksheets/sheet2.xml.
Si sheIde, no es un numero y empieza por xl, entonces se asume que se esta
proporcionando el path completo de la hoja, por ejemplo,
xl/externalLinks/externalLink1.xml, que en Excels dinamicos pueden contener
la informacion que no contienen las hojas visibles.",
Xlx7ZipExtract);
//////////////////////////////////////////////////////////////////////////////

Real Xlx7ZipTest()

//////////////////////////////////////////////////////////////////////////////
Real Xlx7ZipTest(Text inpPth) // Input path, the Xlsx Excel file path
//////////////////////////////////////////////////////////////////////////////
{
  Text cmdTxt = Xlx7zp + " t " + Q(inpPth) + " > " + XlxTmp;
  Text cmdDos = W(cmdTxt);

  Real Show(FALSE, "ERROR"); // No mostrar errores durante el test
  Real cmdExe = System(cmdDos);
  Real Show(TRUE,  "ERROR"); // Volver a mostrar errores

  GT(TextFind(ReadFile(XlxTmp), "Everything is Ok"),0)
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna cierto si el fichero inpPth tiene una estructura PK correcta.",
Xlx7ZipTest);
//////////////////////////////////////////////////////////////////////////////

Real XlxIsExcelXlsx()

//////////////////////////////////////////////////////////////////////////////
Real XlxIsExcelXlsx(Text inpPth) // Input path, the Xlsx Excel file path
//////////////////////////////////////////////////////////////////////////////
{ If(TextEndAt(ToLower(inpPth), ".xlsx"), Xlx7ZipTest(inpPth), FALSE) };
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna cierto si inpPth tiene la extension y estructura PK correctas.",
XlxIsExcelXlsx);
//////////////////////////////////////////////////////////////////////////////

Text XlxReadText()

//////////////////////////////////////////////////////////////////////////////
Text XlxReadText(Text inpPth, // Input path, the Xlsx Excel file path
                 Text sheIde) // Sheet number 1, 2,... or sheet path
//////////////////////////////////////////////////////////////////////////////
{ If(Xlx7ZipExtract(inpPth, sheIde, XlxTmp), ReadFile(XlxTmp), "") };
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna el texto Xml del Excel Xlsx de camino inpPth de su hoja sheIde.",
XlxReadText);
//////////////////////////////////////////////////////////////////////////////

Set XlxReadTable()

//////////////////////////////////////////////////////////////////////////////
Set XlxReadTable(Text inpPth, // Input path, the Xlsx Excel file path
                 Text sheIde) // Sheet number 1, 2,... or sheet path
//////////////////////////////////////////////////////////////////////////////
{
  Text allXml = XlxReadText(inpPth, sheIde);
  Set  sheXml = XlxSplitByTag(allXml, "sheetData");
  If(NE(Card(sheXml), 1), Empty, // Solo puede haber 1
  {
    Text datXml = sheXml[1]; // El contetido con datos
    Set  rowSet = XlxSplitByTag(datXml, "row"); // El conjunto de filas
    EvalSet(rowSet, Set(Text rowXml) { XlxSplitByTag(rowXml, "v") })
  })
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna una tabla, como conjunto de filas de conjuntos de celdas, con el
contenido en texto del Excel Xlsx de camino inpPth de su hoja sheIde.
Se trata de una version simple que puede retornar tablas no extrictamente
rectangulares si hay celdas sin contenido o celdas combinadas.
En caso de error retorna el conjunto vacio.
Usa un metodo simple retornando el contenido de las celdas sin tener en
cuenta la posible existencia de shared strings.",
XlxReadTable);
//////////////////////////////////////////////////////////////////////////////

Set XlxReadShared()

//////////////////////////////////////////////////////////////////////////////
Set XlxReadShared(Text inpPth) // Input path, the Xlsx Excel file path
//////////////////////////////////////////////////////////////////////////////
{
  Text allXml = XlxReadText(inpPth, "xl/sharedStrings.xml");
  Set  shaXml = XlxSplitByTag(allXml, "sst");
  If(NE(Card(shaXml), 1), Empty, // Solo puede haber 1
  {
    Text datXml = shaXml[1];   // El contetido con shared strings
    XlxSplitByTag(datXml, "t") // Lo correcto seria 1º por <si> y 2º por <t>
  })
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna una lista como un conjunto lineal de los shared strings de un fichero
Excel Xlsx.
Esta lista de textos compartido se guarda en el Xml xl/sharedStrings.xml
con el formato:
  <sst...>
    <si><t>Estos son los strings compartidos y</t></si>
    <si><t>enumerados del 0 al n</t></si>
    <si><t>aunque en tol del 1 al n+1</t></si>
  </sst>
En caso de error esta funcion retorna el conjunto vacio.",
XlxReadShared);
//////////////////////////////////////////////////////////////////////////////

Set XlxReadTableShared()

//////////////////////////////////////////////////////////////////////////////
Set XlxReadTableShared(Text inpPth, // Input path, the Xlsx Excel file path
                       Text sheIde) // Sheet number 1, 2,... or sheet path
//////////////////////////////////////////////////////////////////////////////
{
  Set  shaStr = XlxReadShared(inpPth);       // Lista de shared strings
  Real shaLen = Card(shaStr);                // Numero de shared strings

  Text shaGet(Text posTxt) // Numero de posicion como texto
  {
    Real posNum = Eval(posTxt+"+1; "); // En tol empieza en 1 no en cero
    If(posNum > shaLen, "?", shaStr[posNum]) // Retorna ? si se pasa
  };

  Text allXml = XlxReadText(inpPth, sheIde); // Contenido Excel Xmlx
  Set  sheXml = XlxSplitByTag(allXml, "sheetData");
  If(NE(Card(sheXml), 1), Empty, // Solo puede haber 1
  {
    Text datXml = sheXml[1]; // El contetido con datos
    Set  rowSet = XlxSplitByTag(datXml, "row"); // El conjunto de filas
    EvalSet(rowSet, Set(Text rowXml)
    {
      Set  celTab = XlxSplitByTagAtrVal(rowXml, "c"); // Pares atributo valor
      EvalSet(celTab, Text(Set atrVal) // Para todo par atributo valor
      {
        Real atrSha = TextFind(atrVal[1], XlxSha); // Cierto si es shared
        Text valTxt = XlxSplitByTag(atrVal[2], "v")[1]; // Solo hay 1 valor
        If(atrSha, shaGet(valTxt), valTxt) // Shared->buscar, sino es el mismo
      })
    })
  })
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna una tabla, como conjunto de filas de conjuntos de celdas, con el
contenido en texto del Excel Xlsx de camino inpPth de su hoja sheIde.
Se trata de una version simple que puede retornar tablas no extrictamente
rectangulares si hay celdas sin contenido o celdas combinadas.
A diferencia de XlxReadTable() lee previamente la tabla de shared string y
comprueba en cada celda si el contenido es el original o si es un indice a
la tabla de textos compartidos. Estos Xml tienen el formato:
  <c r='A1'><v>Soy un contenido original pero la celda C1 no lo tiene</v></c>
  <c r='B1'><v>Lo marca el atributo t=s y hay que usar el indice 652</v></c>
  <c r='C1' t='s'><v>652</v></c>
En caso de error retorna el conjunto vacio.",
XlxReadTableShared);
//////////////////////////////////////////////////////////////////////////////

Time oriented language

//////////////////////////////////////////////////////////////////////////////
// FILE    : xlx.tol
// AUTHOR  : http://www.asolver.com
// PURPOSE : Lectura basica de ficheros Excel Xlsx. 
// Los Xlsx son ficheros comprimidos y se pueden abrir con WinZip o 7Zip.
// Este codigo usa 7Zip para extraer la hoja de datos requerida 1, 2, 3,...
// Por ejemplo, se puede extraer el contenido de la hoja 1 con el mandato:
// 7z.exe e excel.xlsx xl\worksheets\sheet1.xml -so > _temporal_.xml
// La hoja es un fichero Xml con los tags <sheetData> <row> y <v> (value).
// Por lo que puede convertirse en un conjunto de conjunto de textos.
// Este codigo no realiza especiales comprobaciones:
// a) ni de mayusculas ni minusculas en las etiquetas Xml,
// b) ni de celdas combinadas,
// c) omite las celdas vacias que no se guarden, por lo que el resultado puede
//    no ser rectangular,
// d) tampoco extrae formulas, ni formatos y
// e) todos los campos los retorna en formato de texto, asi, por ejemplo,
//    las fechas se retornan como un numero en formato de texto y
// f) dependiendo de XlxCpm retorna todos los textos compactados o no,
//    de forma independiente a las directrices del tipo xml:space = preserve.
// A partir de este codigo pueden programarse lectores de Xlsx mas avanzados.
// El unico fichero temporal que usa no se borra para facilitar la validacion.
// Hay 2 tipos de funciones:
// a) la que retorna directamente los contenidos y
// b) la que si el contenido de la celda no es un valor sino es el indice a la
//    tabla de shared strings realiza la busqueda en esa tabla y retorna los
//    contenidos reales.
// Para entender el uso de la tabla de sharedStrings en Excel Xlsx puede
// consultarse el sitio web: http://www.sadev.co.za/content
// en reading-and-writing-excel-2007-or-excel-2010-c-series-index
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// CONTROLS
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
Real XlxCmp = TRUE;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Si cierto compacta todos los textos siempre.",
XlxCmp);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Real XlxTra = TRUE;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Si cierto traduce de Xml a Ascii los & < y >.",
XlxTra);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// CONSTANTS
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
Text XlxChr = Char(7);
//////////////////////////////////////////////////////////////////////////////
PutDescription("Caracter separador que se espera unico.",
XlxChr);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Text XlxTmp = "tmp/_xlsx_.tmp";
//////////////////////////////////////////////////////////////////////////////
PutDescription("Fichero temporal que se espera unico.",
XlxTmp);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Text Xlx7zp = "bin/7zip/7z.exe";
//////////////////////////////////////////////////////////////////////////////
PutDescription("Path al progama ejecutable 7 Zip.",
Xlx7zp);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Text XlxSha = "t=\"s\""; 
//////////////////////////////////////////////////////////////////////////////
PutDescription("Atributo shared string con dobles comillas.",
XlxSha);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set  XlxRep = [[ [["&amp;","&"]],
                 [["&lt",  "<"]],
                 [["&gt;", ">"]] ]];
//////////////////////////////////////////////////////////////////////////////
PutDescription("Tabla de reemplazamientos Xml a Ascii.",
XlxRep);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// FUNCTIONS
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
Set  XlxSetCtr(Real newCmp, // Nuevo valor para el control de compactacion
               Real newTra) // Nuevo valor para el control de traduccion
//////////////////////////////////////////////////////////////////////////////
{
  Set  oldVal = SetOfText(Copy(XlxCmp), Copy(XlxTra)); // Valores actuales
  Text(XlxCmp:=Copy(newCmp)); // Memoriza la nueva compactacion
  Text(XlxTra:=Copy(newTra)); // Memoriza la nueva traduccion
  oldVal // Retorna los antiguos valores
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Memoriza los nuevos valores para los controles XlxCmp y XlxTra sobre 
la compactacion y traduccion de los textos leidos de ficheros Excel Xlsx,
que se emplearan a partir de la llamada a esta funcion, esto es, actualiza
los parametros de control.
Retorna los valores anteriores por si se desean restaurar posteriormente.",
XlxSetCtr);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Text XlxFromLblToEnd(Text txtXml, // Original Xml text
                     Text lblIni) // Initial label
//////////////////////////////////////////////////////////////////////////////
{
  Text xml2Asc(Text xmlTxt) { ReplaceTable(xmlTxt, XlxRep) }; // Cambia & < >
  
  Real posIni = TextFind(txtXml, lblIni);
  If(LE(posIni,0), "",
  {
    Real posSub = posIni + TextLength(lblIni);
    Real posEnd = TextLength(txtXml);
    Text subTxt = Sub(txtXml,posSub,posEnd);
    Text subCmp = If(XlxCmp, Compact(subTxt), subTxt); // Compacta si procede
    Text subTra = If(XlxTra, xml2Asc(subCmp), subCmp); // Traduce si procede
    subTra
  })
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna todo el texto a la derecha de la primera ocurrencia de la etiqueta
lblIni en txtXml.
Si la etiqueta lblIni no aparece retorna el texto vacio.",
XlxFromLblToEnd);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Text XlxFromTagToEnd(Text txtXml, // Original Xml text
                     Text tagIni) // Initial tag without < >
//////////////////////////////////////////////////////////////////////////////
{ XlxFromLblToEnd(XlxFromLblToEnd(txtXml, "<"+tagIni), ">") };
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna todo el texto a la derecha de la primera ocurrencia del tag tagIni.
Tiene en cuenta la forma de los tags Xml <tagIni . . .>.
Es adecuada cuando no interesan los atributos del tag.
Si tagIni no aparece o esta mal formado retorna el texto vacio.",
XlxFromTagToEnd);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set XlxFromTagToAtrVal(Text txtXml, // Original Xml text
                       Text tagIni) // Initial tag without < >
//////////////////////////////////////////////////////////////////////////////
{
  Text atrVal = XlxFromLblToEnd(txtXml, "<"+tagIni);
  Text atrTxt = Sub(atrVal, 1, TextFind(atrVal, ">")); // De > a la izquierda
  Text valTxt = XlxFromLblToEnd(atrVal, ">");          // De > a la derecha
  SetOfText(atrTxt, valTxt)
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna un par con el contenido de los atributos del tag y el valor hasta el
final, por ejemplo, <c a=1>valor a la derecha -> [a=1, valor a la derecha].
Es adecuada cuando si interesan los atributos del tag.
Si tagIni no aparece o esta mal formado retorna textos vacios.",
XlxFromTagToAtrVal);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set XlxSplitByTag(Text txtXml, // Original Xml text
                  Text tagBrk) // Tag for break, without < </ >
//////////////////////////////////////////////////////////////////////////////
{
  Set tokSet = Tokenizer(Replace(txtXml, "</"+tagBrk+">", XlxChr), XlxChr);
  For(1, Card(tokSet)-1, Text(Real posSet)
      { XlxFromTagToEnd(tokSet[posSet], tagBrk) })
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna el conjunto de todos los textos entre <tagBrk> y </tagBrk>.
Es adecuada cuando no interesan los atributos del tag.
  XlxSplitByTag(a<v>1</v>b<v>2</v>c<v>3</v>d, v)-> [1,2,3]
pero no los textos a b c d.",
XlxSplitByTag);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set XlxSplitByTagAtrVal(Text txtXml, // Original Xml text
                        Text tagBrk) // Tag for break, without < </ >
//////////////////////////////////////////////////////////////////////////////
{
  Set tokSet = Tokenizer(Replace(txtXml, "</"+tagBrk+">", XlxChr), XlxChr);
  For(1, Card(tokSet)-1, Set(Real posSet)
      { XlxFromTagToAtrVal(tokSet[posSet], tagBrk) })
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna el conjunto de pares formados por (todos los atributos,
valor del contenido) de un tag XML.
Siendo:
a) los atributos del tag <tagBrk...a1=1 a2=2...aN=n> y
b) el texto entre <tagBrk...> y </tagBrk> el valor de su contenido.
Es adecuada cuando si interesan los atributos del tag.",
XlxSplitByTagAtrVal);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Real Xlx7ZipExtract(Text inpPth, // Input path, the Xlsx Excel file path
                    Text sheIde, // Sheet number 1, 2,... or sheet path
                    Text outPth) // Output path, the Xml output file
//////////////////////////////////////////////////////////////////////////////
{
  Text xmlPth = If(TextBeginWith(sheIde, "xl"), sheIde, // Dan path completo
                "xl/worksheets/sheet"+sheIde+".xml");

  Text cmdTxt = Xlx7zp + " e " + Q(inpPth) + " " + xmlPth +  // Extrae de
                " -so > " + outPth;                          // Vuelca en
  Text cmdDos = W(cmdTxt);
  Text WriteLn(cmdDos);
  System(cmdDos)
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna cierto si puede extraer la hoja numero sheIde del fichero Excel Xlsx
de camino inpPth y guardarla en el fichero de salida de camino outPth.
Para los casos sencillos sheIde puede ser un numero en forma de texto,
por ejemplo si es un 2 se asume xl/worksheets/sheet2.xml.
Si sheIde, no es un numero y empieza por xl, entonces se asume que se esta
proporcionando el path completo de la hoja, por ejemplo,
xl/externalLinks/externalLink1.xml, que en Excels dinamicos pueden contener
la informacion que no contienen las hojas visibles.",
Xlx7ZipExtract);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Real Xlx7ZipTest(Text inpPth) // Input path, the Xlsx Excel file path
//////////////////////////////////////////////////////////////////////////////
{
  Text cmdTxt = Xlx7zp + " t " + Q(inpPth) + " > " + XlxTmp;
  Text cmdDos = W(cmdTxt);

  Real Show(FALSE, "ERROR"); // No mostrar errores durante el test
  Real cmdExe = System(cmdDos);
  Real Show(TRUE,  "ERROR"); // Volver a mostrar errores

  GT(TextFind(ReadFile(XlxTmp), "Everything is Ok"),0)
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna cierto si el fichero inpPth tiene una estructura PK correcta.",
Xlx7ZipTest);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Real XlxIsExcelXlsx(Text inpPth) // Input path, the Xlsx Excel file path
//////////////////////////////////////////////////////////////////////////////
{ If(TextEndAt(ToLower(inpPth), ".xlsx"), Xlx7ZipTest(inpPth), FALSE) };
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna cierto si inpPth tiene la extension y estructura PK correctas.",
XlxIsExcelXlsx);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Text XlxReadText(Text inpPth, // Input path, the Xlsx Excel file path
                 Text sheIde) // Sheet number 1, 2,... or sheet path
//////////////////////////////////////////////////////////////////////////////
{ If(Xlx7ZipExtract(inpPth, sheIde, XlxTmp), ReadFile(XlxTmp), "") };
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna el texto Xml del Excel Xlsx de camino inpPth de su hoja sheIde.",
XlxReadText);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set XlxReadTable(Text inpPth, // Input path, the Xlsx Excel file path
                 Text sheIde) // Sheet number 1, 2,... or sheet path
//////////////////////////////////////////////////////////////////////////////
{
  Text allXml = XlxReadText(inpPth, sheIde);
  Set  sheXml = XlxSplitByTag(allXml, "sheetData");
  If(NE(Card(sheXml), 1), Empty, // Solo puede haber 1
  {
    Text datXml = sheXml[1]; // El contetido con datos
    Set  rowSet = XlxSplitByTag(datXml, "row"); // El conjunto de filas
    EvalSet(rowSet, Set(Text rowXml) { XlxSplitByTag(rowXml, "v") })
  })
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna una tabla, como conjunto de filas de conjuntos de celdas, con el
contenido en texto del Excel Xlsx de camino inpPth de su hoja sheIde.
Se trata de una version simple que puede retornar tablas no extrictamente
rectangulares si hay celdas sin contenido o celdas combinadas.
En caso de error retorna el conjunto vacio.
Usa un metodo simple retornando el contenido de las celdas sin tener en
cuenta la posible existencia de shared strings.",
XlxReadTable);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set XlxReadShared(Text inpPth) // Input path, the Xlsx Excel file path
//////////////////////////////////////////////////////////////////////////////
{
  Text allXml = XlxReadText(inpPth, "xl/sharedStrings.xml");
  Set  shaXml = XlxSplitByTag(allXml, "sst");
  If(NE(Card(shaXml), 1), Empty, // Solo puede haber 1
  {
    Text datXml = shaXml[1];   // El contetido con shared strings
    XlxSplitByTag(datXml, "t") // Lo correcto seria 1º por <si> y 2º por <t>
  })
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna una lista como un conjunto lineal de los shared strings de un fichero
Excel Xlsx.
Esta lista de textos compartido se guarda en el Xml xl/sharedStrings.xml
con el formato:
  <sst...>
    <si><t>Estos son los strings compartidos y</t></si>
    <si><t>enumerados del 0 al n</t></si>
    <si><t>aunque en tol del 1 al n+1</t></si>
  </sst>
En caso de error esta funcion retorna el conjunto vacio.",
XlxReadShared);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set XlxReadTableShared(Text inpPth, // Input path, the Xlsx Excel file path
                       Text sheIde) // Sheet number 1, 2,... or sheet path
//////////////////////////////////////////////////////////////////////////////
{
  Set  shaStr = XlxReadShared(inpPth);       // Lista de shared strings
  Real shaLen = Card(shaStr);                // Numero de shared strings

  Text shaGet(Text posTxt) // Numero de posicion como texto
  {
    Real posNum = Eval(posTxt+"+1; "); // En tol empieza en 1 no en cero
    If(posNum > shaLen, "?", shaStr[posNum]) // Retorna ? si se pasa
  };

  Text allXml = XlxReadText(inpPth, sheIde); // Contenido Excel Xmlx
  Set  sheXml = XlxSplitByTag(allXml, "sheetData");
  If(NE(Card(sheXml), 1), Empty, // Solo puede haber 1
  {
    Text datXml = sheXml[1]; // El contetido con datos
    Set  rowSet = XlxSplitByTag(datXml, "row"); // El conjunto de filas
    EvalSet(rowSet, Set(Text rowXml)
    {
      Set  celTab = XlxSplitByTagAtrVal(rowXml, "c"); // Pares atributo valor
      EvalSet(celTab, Text(Set atrVal) // Para todo par atributo valor
      {
        Real atrSha = TextFind(atrVal[1], XlxSha); // Cierto si es shared
        Text valTxt = XlxSplitByTag(atrVal[2], "v")[1]; // Solo hay 1 valor
        If(atrSha, shaGet(valTxt), valTxt) // Shared->buscar, sino es el mismo
      })
    })
  })
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna una tabla, como conjunto de filas de conjuntos de celdas, con el
contenido en texto del Excel Xlsx de camino inpPth de su hoja sheIde.
Se trata de una version simple que puede retornar tablas no extrictamente
rectangulares si hay celdas sin contenido o celdas combinadas.
A diferencia de XlxReadTable() lee previamente la tabla de shared string y
comprueba en cada celda si el contenido es el original o si es un indice a
la tabla de textos compartidos. Estos Xml tienen el formato:
  <c r='A1'><v>Soy un contenido original pero la celda C1 no lo tiene</v></c>
  <c r='B1'><v>Lo marca el atributo t=s y hay que usar el indice 652</v></c>
  <c r='C1' t='s'><v>652</v></c>
En caso de error retorna el conjunto vacio.",
XlxReadTableShared);
//////////////////////////////////////////////////////////////////////////////

Árbol de ficheros

Xlsx.Reader funciones de lectura desde Tol de hojas en Excel Xlsx de Microsoft

  • make.tol programa de test de las funciones de lectura de hojas Xlsx
  • make.bat mandato de ejecución del programa de test de lectura Excel
  • tol directorios de funciones desarrolladas en Time Oriented Languaje
    • cmm directorio con las funciones comunes
      • xlx.tol librería de funciones para descomprimir y leer Excel Xlx
    • inc.tol fichero con la orden de inclusión del fichero Tol xlx.tol
  • excel.xlsx.descompresor.png Excel abierto y marcados los Xml de datos y strings compartidos
  • xlsx_reader.pdf documento de funciones de descompresión y lectura Xml de Excel

2015 asolver.com | Aviso legal | XHTML | Δ Θ Ξ | Creative Commons | Mapa y funciones del sitio

Tol