109 lines
4.4 KiB
C#
109 lines
4.4 KiB
C#
using System.Text;
|
|||
|
|
using System.Xml.Linq;
|
||
|
|
using ExcelDataReader;
|
||
|
|
|
||
|
|
namespace CadSearchGui;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Converte il file "Distinta Base" esportato dal gestionale (SpreadsheetML
|
||
|
|
/// XML con estensione .xls/.xml, oppure .xls/.xlsx binario vero) nelle sole
|
||
|
|
/// colonne Componente/Descrizione in CSV.
|
||
|
|
/// </summary>
|
||
|
|
static class DistintaBaseImporter
|
||
|
|
{
|
||
|
|
private static readonly XNamespace Ss = "urn:schemas-microsoft-com:office:spreadsheet";
|
||
|
|
private const string NomeFoglio = "Distinta Base";
|
||
|
|
|
||
|
|
static DistintaBaseImporter()
|
||
|
|
{
|
||
|
|
Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
|
||
|
|
}
|
||
|
|
|
||
|
|
public static (string PercorsoCsv, List<(string Componente, string Descrizione)> Righe) ConvertiInCsv(string percorsoInput)
|
||
|
|
{
|
||
|
|
var righeGrezze = EImmagineSpreadsheetMl(percorsoInput)
|
||
|
|
? LeggiRigheSpreadsheetMl(percorsoInput)
|
||
|
|
: LeggiRigheExcelBinario(percorsoInput);
|
||
|
|
|
||
|
|
var righe = righeGrezze.Skip(1) // salta l'intestazione
|
||
|
|
.Where(r => r.Componente.Length > 0 || r.Descrizione.Length > 0)
|
||
|
|
.ToList();
|
||
|
|
|
||
|
|
var percorsoCsv = Path.Combine(
|
||
|
|
Path.GetDirectoryName(Path.GetFullPath(percorsoInput))!,
|
||
|
|
Path.GetFileNameWithoutExtension(percorsoInput) + ".csv");
|
||
|
|
|
||
|
|
using var writer = new StreamWriter(percorsoCsv, false, Encoding.UTF8);
|
||
|
|
writer.WriteLine("Componente;Descrizione");
|
||
|
|
foreach (var (componente, descrizione) in righe)
|
||
|
|
{
|
||
|
|
writer.WriteLine($"{EscapeCsv(componente)};{EscapeCsv(descrizione)}");
|
||
|
|
}
|
||
|
|
|
||
|
|
return (percorsoCsv, righe);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>I file XML "SpreadsheetML" iniziano con l'intestazione XML testuale;
|
||
|
|
/// i file .xls/.xlsx binari veri iniziano invece con una firma binaria (OLE2 o ZIP).</summary>
|
||
|
|
private static bool EImmagineSpreadsheetMl(string percorso)
|
||
|
|
{
|
||
|
|
Span<byte> primiByte = stackalloc byte[5];
|
||
|
|
using var stream = File.OpenRead(percorso);
|
||
|
|
var letti = stream.Read(primiByte);
|
||
|
|
return letti >= 5 && Encoding.ASCII.GetString(primiByte) == "<?xml";
|
||
|
|
}
|
||
|
|
|
||
|
|
private static List<(string Componente, string Descrizione)> LeggiRigheSpreadsheetMl(string percorsoInput)
|
||
|
|
{
|
||
|
|
var doc = XDocument.Load(percorsoInput);
|
||
|
|
var foglio = doc.Descendants(Ss + "Worksheet")
|
||
|
|
.FirstOrDefault(w => (string?)w.Attribute(Ss + "Name") == NomeFoglio)
|
||
|
|
?? throw new InvalidDataException($"Foglio '{NomeFoglio}' non trovato nel file.");
|
||
|
|
|
||
|
|
var righeXml = foglio.Descendants(Ss + "Row").ToList();
|
||
|
|
if (righeXml.Count == 0)
|
||
|
|
throw new InvalidDataException($"Il foglio '{NomeFoglio}' non contiene righe.");
|
||
|
|
|
||
|
|
return righeXml.Select(LeggiColonneBeCSpreadsheetMl).ToList();
|
||
|
|
}
|
||
|
|
|
||
|
|
private static (string Componente, string Descrizione) LeggiColonneBeCSpreadsheetMl(XElement riga)
|
||
|
|
{
|
||
|
|
string b = "", c = "";
|
||
|
|
int colonna = 0;
|
||
|
|
foreach (var cella in riga.Elements(Ss + "Cell"))
|
||
|
|
{
|
||
|
|
// ss:Index salta le celle vuote iniziali: senza attributo la colonna è quella precedente + 1
|
||
|
|
var indice = cella.Attribute(Ss + "Index");
|
||
|
|
colonna = indice != null ? int.Parse(indice.Value) : colonna + 1;
|
||
|
|
if (colonna == 2) b = cella.Element(Ss + "Data")?.Value ?? "";
|
||
|
|
else if (colonna == 3) c = cella.Element(Ss + "Data")?.Value ?? "";
|
||
|
|
}
|
||
|
|
return (b, c);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static List<(string Componente, string Descrizione)> LeggiRigheExcelBinario(string percorsoInput)
|
||
|
|
{
|
||
|
|
using var stream = File.Open(percorsoInput, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||
|
|
using var reader = ExcelReaderFactory.CreateReader(stream);
|
||
|
|
var dataSet = reader.AsDataSet();
|
||
|
|
var tabella = dataSet.Tables[NomeFoglio]
|
||
|
|
?? throw new InvalidDataException($"Foglio '{NomeFoglio}' non trovato nel file.");
|
||
|
|
|
||
|
|
var righe = new List<(string Componente, string Descrizione)>();
|
||
|
|
foreach (System.Data.DataRow riga in tabella.Rows)
|
||
|
|
{
|
||
|
|
var b = riga.Table.Columns.Count > 1 ? riga[1]?.ToString() ?? "" : "";
|
||
|
|
var c = riga.Table.Columns.Count > 2 ? riga[2]?.ToString() ?? "" : "";
|
||
|
|
righe.Add((b, c));
|
||
|
|
}
|
||
|
|
return righe;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static string EscapeCsv(string valore)
|
||
|
|
{
|
||
|
|
if (valore.Contains(';') || valore.Contains('"') || valore.Contains('\n'))
|
||
|
|
return $"\"{valore.Replace("\"", "\"\"")}\"";
|
||
|
|
return valore;
|
||
|
|
}
|
||
|
|
}
|