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
Variables de control
Real XlxCmpReal XlxTraConstantes
Text XlxChrText XlxTmpText Xlx7zpText XlxShaSet XlxRepFunciones
Set XlxSetCtr(Real newCmp, Real newTra)Text XlxFromLblToEnd(Text txtXml, Text lblIni)Text XlxFromTagToEnd(Text txtXml, Text tagIni)Set XlxFromTagToAtrVal(Text txtXml, Text tagIni)Set XlxSplitByTag(Text txtXml, Text tagBrk)Set XlxSplitByTagAtrVal(Text txtXml, Text tagBrk)Real Xlx7ZipExtract(Text inpPth, Text sheIde, Text outPth)Real Xlx7ZipTest(Text inpPth)Real XlxIsExcelXlsx(Text inpPth)Text XlxReadText(Text inpPth, Text sheIde)Set XlxReadTable(Text inpPth, Text sheIde)Set XlxReadShared(Text inpPth)Set XlxReadTableShared(Text inpPth, Text sheIde)//////////////////////////////////////////////////////////////////////////////
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);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
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 = [[ [["&","&"]],
[["<", "<"]],
[[">", ">"]] ]];
//////////////////////////////////////////////////////////////////////////////
PutDescription("Tabla de reemplazamientos Xml a Ascii.",
XlxRep);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
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);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// 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 = [[ [["&","&"]],
[["<", "<"]],
[[">", ">"]] ]];
//////////////////////////////////////////////////////////////////////////////
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);
//////////////////////////////////////////////////////////////////////////////
Xlsx.Reader funciones de lectura desde Tol de hojas en Excel Xlsx de Microsoft
2015 asolver.com | Aviso legal | XHTML | Δ Θ Ξ | Creative Commons | Mapa y funciones del sitio