BusinessMgr web apps
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,206 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Sarand.Net.Standard.Proc.Excel
|
||||
{
|
||||
//=======================================================================
|
||||
// Definitions.
|
||||
public enum SaExcelLogicalUnit
|
||||
{
|
||||
Point,
|
||||
Pixel,
|
||||
Cm,
|
||||
Inch,
|
||||
//CharWidth, // Not supported.
|
||||
};
|
||||
//=======================================================================
|
||||
/// <summary>Spreadsheet file format.
|
||||
/// <para>Ref. Microsoft.Office.Interop.Excel.XlFileFormat</para></summary>
|
||||
public enum SaXlFileFormat
|
||||
{
|
||||
Default = 0,
|
||||
/// <summary>Without macro's in 2007-2013 [xlsx]. Value: 51.</summary>
|
||||
OpenXMLWorkbook = XlFileFormat.xlOpenXMLWorkbook,
|
||||
/// <summary>With or without macro's in 2007-2013 [xlsm]. Value: 52.</summary>
|
||||
OpenXMLWorkbookMacroEnabled = XlFileFormat.xlOpenXMLWorkbookMacroEnabled,
|
||||
/// <summary>Excel Binary Workbook in 2007-2013 with or without macro's [xlsb]. Value: 50.</summary>
|
||||
Excel12 = XlFileFormat.xlExcel12,
|
||||
/// <summary>97-2003 format in Excel 2007-2013 [xls]. Value: 56.</summary>
|
||||
Excel8 = XlFileFormat.xlExcel8,
|
||||
/// <summary>CSV format. Value: 6.</summary>
|
||||
CSV = XlFileFormat.xlCSV,
|
||||
};
|
||||
/// <summary>
|
||||
/// Specifies the page orientation when the worksheet is printed.
|
||||
/// <para>Ref. Microsoft.Office.Interop.Excel.XlPageOrientation</para>
|
||||
/// </summary>
|
||||
public enum SaXlPageOrientation
|
||||
{
|
||||
NotSpecified = int.MinValue,
|
||||
xlPortrait = XlPageOrientation.xlPortrait,
|
||||
xlLandscape = XlPageOrientation.xlLandscape
|
||||
}
|
||||
/// <summary>
|
||||
/// Specifies the weight of the border around a range.
|
||||
/// <para>Ref. Microsoft.Office.Interop.Excel.XlBorderWeight</para>
|
||||
/// </summary>
|
||||
public enum SaXlBorderWeight
|
||||
{
|
||||
NotSpecified = int.MinValue,
|
||||
Hairline = XlBorderWeight.xlHairline,
|
||||
Thin = XlBorderWeight.xlThin,
|
||||
Medium = XlBorderWeight.xlMedium,
|
||||
Thick = XlBorderWeight.xlThick
|
||||
}
|
||||
/// <summary>
|
||||
/// Specifies the line style for the border.
|
||||
/// <para>Ref. Microsoft.Office.Interop.Excel.XlLineStyle</para>
|
||||
/// </summary>
|
||||
public enum SaXlLineStyle
|
||||
{
|
||||
NotSpecified = int.MinValue,
|
||||
None = XlLineStyle.xlLineStyleNone,
|
||||
Double = XlLineStyle.xlDouble,
|
||||
Dot = XlLineStyle.xlDot,
|
||||
Dash = XlLineStyle.xlDash,
|
||||
Continuous = XlLineStyle.xlContinuous,
|
||||
DashDot = XlLineStyle.xlDashDot,
|
||||
DashDotDot = XlLineStyle.xlDashDotDot,
|
||||
SlantDashDot = XlLineStyle.xlSlantDashDot,
|
||||
}
|
||||
/// <summary>
|
||||
/// Specifies the interior pattern of a chart or interior object.
|
||||
/// <para>Ref. Microsoft.Office.Interop.Excel.XlPattern</para>
|
||||
/// </summary>
|
||||
public enum SaXlPattern
|
||||
{
|
||||
NotSpecified = int.MinValue,
|
||||
/// <summary>No pattern.</summary>
|
||||
None = XlPattern.xlPatternNone,
|
||||
/// <summary>Excel controls the pattern.</summary>
|
||||
Automatic = XlPattern.xlPatternAutomatic,
|
||||
/// <summary>8% gray.</summary>
|
||||
Gray8 = XlPattern.xlPatternGray8,
|
||||
/// <summary>16% gray.</summary>
|
||||
Gray16 = XlPattern.xlPatternGray16,
|
||||
/// <summary>25% gray.</summary>
|
||||
Gray25 = XlPattern.xlPatternGray25,
|
||||
/// <summary>50% gray.</summary>
|
||||
Gray50 = XlPattern.xlPatternGray50,
|
||||
/// <summary>75% gray.</summary>
|
||||
Gray75 = XlPattern.xlPatternGray75,
|
||||
/// <summary>75% dark moiré.</summary>
|
||||
SemiGray75 = XlPattern.xlPatternSemiGray75,
|
||||
/// <summary>Solid color.</summary>
|
||||
Solid = XlPattern.xlPatternSolid,
|
||||
/// <summary>Dark vertical bars.</summary>
|
||||
Vertical = XlPattern.xlPatternVertical,
|
||||
/// <summary>Dark horizontal lines.</summary>
|
||||
Horizontal = XlPattern.xlPatternHorizontal,
|
||||
/// <summary>Dark diagonal lines running from the lower left to the upper right.</summary>
|
||||
Up = XlPattern.xlPatternUp,
|
||||
/// <summary>Dark diagonal lines running from the upper left to the lower right.</summary>
|
||||
Down = XlPattern.xlPatternDown,
|
||||
/// <summary>Checkerboard.</summary>
|
||||
Checker = XlPattern.xlPatternChecker,
|
||||
/// <summary>Light horizontal lines.</summary>
|
||||
LightHorizontal = XlPattern.xlPatternLightHorizontal,
|
||||
/// <summary>Light vertical bars.</summary>
|
||||
LightVertical = XlPattern.xlPatternLightVertical,
|
||||
/// <summary>Light diagonal lines running from the upper left to the lower right.</summary>
|
||||
LightDown = XlPattern.xlPatternLightDown,
|
||||
/// <summary>Light diagonal lines running from the lower left to the upper right.</summary>
|
||||
LightUp = XlPattern.xlPatternLightUp,
|
||||
/// <summary>Grid.</summary>
|
||||
Grid = XlPattern.xlPatternGrid,
|
||||
/// <summary>Criss-cross lines.</summary>
|
||||
CrissCross = XlPattern.xlPatternCrissCross,
|
||||
LinearGradient = XlPattern.xlPatternLinearGradient,
|
||||
RectangularGradient = XlPattern.xlPatternRectangularGradient
|
||||
}
|
||||
/// <summary>
|
||||
/// Colour index.
|
||||
/// <para>Ref. Microsoft.Office.Interop.Excel.XlColorIndex.</para>
|
||||
/// </summary>
|
||||
public enum SaXlColourIndex
|
||||
{
|
||||
NotSpecified = int.MinValue,
|
||||
/// <summary>No color. -4142, &HFFFFEFD2.</summary>
|
||||
None = XlColorIndex.xlColorIndexNone,
|
||||
/// <summary>Automatic color. -4105, &HFFFFEFF7.</summary>
|
||||
Automatic = XlColorIndex.xlColorIndexAutomatic,
|
||||
Black = 1,
|
||||
White = 2,
|
||||
Red = 3,
|
||||
BrightGreen = 4,
|
||||
Blue = 5,
|
||||
Yellow = 6,
|
||||
Pink = 7,
|
||||
Magenta = 7,
|
||||
Turqoise = 8,
|
||||
Cyan = 8,
|
||||
DarkRed = 9,
|
||||
Green = 10,
|
||||
DarkBlue = 11,
|
||||
DarkYellow = 12,
|
||||
Violet = 13,
|
||||
Teal = 14,
|
||||
Gray25 = 15,
|
||||
Gray50 = 16,
|
||||
SkyBlue = 33,
|
||||
LightTurqoise = 34,
|
||||
LightGreen = 35,
|
||||
LightYellow = 36,
|
||||
PaleBlue = 37,
|
||||
Rose = 38,
|
||||
Lavendar = 39,
|
||||
Tan = 40,
|
||||
LightBlue = 41,
|
||||
Aqua = 42,
|
||||
Lime = 43,
|
||||
Gold = 44,
|
||||
LightOrange = 45,
|
||||
Orange = 46,
|
||||
BlueGray = 47,
|
||||
Gray40 = 48,
|
||||
DarkTeal = 49,
|
||||
SeaGreen = 50,
|
||||
DarkGreen = 51,
|
||||
OliveGreen = 52,
|
||||
Brown = 53,
|
||||
Plum = 54,
|
||||
Indigo = 55,
|
||||
Gray80 = 56,
|
||||
};
|
||||
/// <summary>
|
||||
/// RGB colour value.
|
||||
/// <para>Ref. Microsoft.Office.Interop.Excel.XlRgbColor.</para>
|
||||
/// </summary>
|
||||
public enum SaXlRgbColor
|
||||
{
|
||||
NotSpecified = int.MinValue,
|
||||
Red = XlRgbColor.rgbRed,
|
||||
}
|
||||
/// <summary>
|
||||
/// Specifies the type of underline applied to a font.
|
||||
/// <para>Ref. Microsoft.Office.Interop.Excel.XlUnderlineStyle</para>
|
||||
/// </summary>
|
||||
public enum SaXlUnderlineStyle
|
||||
{
|
||||
/// <summary>No underlining.</summary>
|
||||
None = XlUnderlineStyle.xlUnderlineStyleNone,
|
||||
/// <summary>Double thick underline.</summary>
|
||||
Double = XlUnderlineStyle.xlUnderlineStyleDouble,
|
||||
/// <summary>Single underlining.</summary>
|
||||
Single = XlUnderlineStyle.xlUnderlineStyleSingle,
|
||||
/// <summary>Single accounting - Not supported.</summary>
|
||||
SingleAccounting = XlUnderlineStyle.xlUnderlineStyleSingleAccounting,
|
||||
/// <summary>Double accounting - Two thin underlines placed close together.</summary>
|
||||
DoubleAccounting = XlUnderlineStyle.xlUnderlineStyleDoubleAccounting
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,569 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
|
||||
namespace Sarand.Net.Standard.Proc.Excel
|
||||
{
|
||||
//=======================================================================
|
||||
// Some Excel enumerated values are replaced with local integers or
|
||||
// equivalent enum to avoid errors related to:
|
||||
// "Cannot be used across assembly boundaries because it has a
|
||||
// generic type parameter that is an embedded interop type."
|
||||
// eg. SaMsExcelItemAttr.HorizontalAlignment: short instead of XlHAlign.
|
||||
//=======================================================================
|
||||
public class SaMsExcelRange
|
||||
{
|
||||
public uint ColFrom { get; set; } = 0;
|
||||
public uint ColTo { get; set; } = 0;
|
||||
public uint RowFrom { get; set; } = 0;
|
||||
public uint RowTo { get; set; } = 0;
|
||||
public SaMsExcelRange() { }
|
||||
public SaMsExcelRange(uint colPos, uint rowPos)
|
||||
{
|
||||
ColFrom = colPos;
|
||||
ColTo = colPos;
|
||||
RowFrom = rowPos;
|
||||
RowTo = rowPos;
|
||||
}
|
||||
public SaMsExcelRange(uint colPosFrom, uint rowPosFrom, uint colPosTo, uint rowPosTo)
|
||||
{
|
||||
ColFrom = colPosFrom;
|
||||
ColTo = colPosTo;
|
||||
RowFrom = rowPosFrom;
|
||||
RowTo = rowPosTo;
|
||||
}
|
||||
}
|
||||
//=======================================================================
|
||||
public class SaMsExcelPageSetup_Config
|
||||
{
|
||||
public SaMsExcelPageSetup_Config()
|
||||
{
|
||||
}
|
||||
/// <summary>Orientation: xlPortrait (1) or xlLandscape (2). Default: Not specified (ignore)</summary>
|
||||
public SaXlPageOrientation Orientation { get; set; } = SaXlPageOrientation.NotSpecified;
|
||||
/// <summary>Logical unit. Default: Point.</summary>
|
||||
public SaExcelLogicalUnit Unit { get; set; } = SaExcelLogicalUnit.Point;
|
||||
// Headers and footers.
|
||||
// NB Font & size and page no and total pages can be encoded as: '&"Batang,Regular"&14Page &P of &N'
|
||||
public String HeaderLeft { get; set; } = "";
|
||||
public String HeaderCenter { get; set; } = "";
|
||||
public String HeaderRight { get; set; } = "";
|
||||
public String FooterLeft { get; set; } = "";
|
||||
public String FooterCenter { get; set; } = "";
|
||||
public String FooterRight { get; set; } = "";
|
||||
// Margins.
|
||||
// Negative values leave current value (default=-1.0).
|
||||
public double MarginLeft { get; set; } = -1.0;
|
||||
public double MarginRight { get; set; } = -1.0;
|
||||
public double MarginTop { get; set; } = -1.0;
|
||||
public double MarginBottom { get; set; } = -1.0;
|
||||
public double MarginHeader { get; set; } = -1.0;
|
||||
public double MarginFooter { get; set; } = -1.0;
|
||||
// Negative values to leave current value, zero to clear (default=-1).
|
||||
public int PrintTitleRowFrom { get; set; } = -1;
|
||||
public int PrintTitleRowTo { get; set; } = -1;
|
||||
public int PrintTitleColFrom { get; set; } = -1;
|
||||
public int PrintTitleColTo { get; set; } = -1;
|
||||
// Zoom or 'fit to' pages.
|
||||
/// <summary>Zoom: 40 = 40%, default: -1.</summary>
|
||||
public int Zoom { get; set; } = -1;
|
||||
/// <summary>Fit to pages - Tall. 1 = 1 page tall, default = -1. [ignored if zoom > 0]</summary>
|
||||
public int FitToPagesTall { get; set; } = -1;
|
||||
/// <summary>Fit to pages - Wide. 1 = 1 page wide, default = -1. [ignored if zoom > 0]</summary>
|
||||
public int FitToPagesWide { get; set; } = -1;
|
||||
}
|
||||
//=======================================================================
|
||||
public class SaMsExcelColumnHeading_Config
|
||||
{
|
||||
public double ColumnWidthPixelsPerCm { get; set; } = 43.0; // Between 10 and 100
|
||||
public uint FirstHeadingRow { get; set; } = 1; // Must be > 0
|
||||
public uint FirstHeadingColumn { get; set; } = 1; // Must be > 0
|
||||
public uint FreezeColumn { get; set; } = 0; // 0 = don't freeze
|
||||
public short HeadingFontSize { get; set; } = 9;
|
||||
public bool HeadingTextBold { get; set; } = true;
|
||||
public bool HeadingTextWrap { get; set; } = true;
|
||||
/// <summary>Cell font colour index, ref. XlColorIndex</summary>
|
||||
public SaXlColourIndex InteriorColourIndex { get; set; } = SaXlColourIndex.NotSpecified;
|
||||
/// <summary>Cell RGB colour value, ref. XlRgbColor. Overrides colour index if changed from default value.</summary>
|
||||
public int? InteriorColour { get; set; } = null;
|
||||
public SaXlBorderWeight BorderWeight { get; set; } = SaXlBorderWeight.NotSpecified;
|
||||
public bool SetColumnWidths { get; set; } = true;
|
||||
public bool SetColumnAlignment { get; set; } = true;
|
||||
public bool SetColumnDataTypeFormat { get; set; } = true; // '@' for strings, '#,##0.00' for numeric depending on thousands/decimals
|
||||
public String CellFormatDate { get; set; } = "d-mmm-yy";
|
||||
public String CellFormatTime { get; set; } = "hh:mm";
|
||||
public String CellFormatDateTimeDelim { get; set; } = " ";
|
||||
}
|
||||
//=======================================================================
|
||||
public class SaMsExcelImage_Config
|
||||
{
|
||||
public SaMsExcelImage_Config() { }
|
||||
public String ImagePath { get; set; } = "";
|
||||
/// <summary>Column to insert image. Default: 0 (current position).</summary>
|
||||
public uint ColPos { get; set; } = 0;
|
||||
/// <summary>Row to insert image. Default: 0 (current position).</summary>
|
||||
public uint RowPos { get; set; } = 0;
|
||||
/// <summary>Image dimension units. Default: Point.</summary>
|
||||
public SaExcelLogicalUnit Unit { get; set; } = SaExcelLogicalUnit.Point;
|
||||
public double TargetWidth { get; set; } = 0.0;
|
||||
public double TargetHeight { get; set; } = 0.0;
|
||||
public double MaxWidth { get; set; } = 0.0;
|
||||
public double MaxHeight { get; set; } = 0.0;
|
||||
};
|
||||
//=======================================================================
|
||||
public class SaMsExcelBorderAttr
|
||||
{
|
||||
public SaMsExcelBorderAttr(XlBordersIndex index)
|
||||
{
|
||||
Index = index;
|
||||
}
|
||||
public bool IsSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
// Any attributes specified.
|
||||
if (Weight != SaXlBorderWeight.NotSpecified) return true;
|
||||
if (LineStyle != SaXlLineStyle.NotSpecified) return true;
|
||||
if (ColorIndex != SaXlColourIndex.NotSpecified) return true;
|
||||
if (Color != null) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>Border position. XlBordersIndex.xlEdgeLeft etc</summary>
|
||||
public XlBordersIndex Index { get; }
|
||||
/// <summary>Border thickness. XlBorderWeight.xlThin, XlBorderWeight.xlMedium etc.</summary>
|
||||
public SaXlBorderWeight Weight { get; set; } = SaXlBorderWeight.NotSpecified;
|
||||
/// <summary>Border line style. XlLineStyle.xlNone, XlLineStyle.xlContinuous, XlLineStyle.xlDash etc.</summary>
|
||||
public SaXlLineStyle LineStyle { get; set; } = SaXlLineStyle.NotSpecified;
|
||||
/// <summary>Border colour index, re. XlColorIndex. Black = 1 etc.</summary>
|
||||
public SaXlColourIndex ColorIndex { get; set; } = SaXlColourIndex.NotSpecified;
|
||||
/// <summary>Border RGB colour value, ref. XlRgbColor. Overrides colour index if changed from default value.</summary>
|
||||
public int? Color { get; set; } = null;
|
||||
}
|
||||
//=======================================================================
|
||||
public class SaMsExcelFontAttr
|
||||
{
|
||||
/// <summary>Font name. Arial etc.</summary>
|
||||
public String FontName { get; set; } = String.Empty;
|
||||
/// <summary>Font style. Regular etc.</summary>
|
||||
public String FontStyle { get; set; } = String.Empty;
|
||||
public short? FontSize { get; set; } = null;
|
||||
/// <summary>Font colour index, ref. XlColorIndex.</summary>
|
||||
public SaXlColourIndex FontColourIndex { get; set; } = SaXlColourIndex.NotSpecified;
|
||||
/// <summary>Font RGB colour value, ref. XlRgbColor. Overrides colour index if changed from default value.</summary>
|
||||
public int? FontColor { get; set; } = null;
|
||||
public bool? Bold { get; set; } = null;
|
||||
public bool? Strikethrough { get; set; } = null;
|
||||
public bool? Superscript { get; set; } = null;
|
||||
public bool? Subscript { get; set; } = null;
|
||||
public bool? OutlineFont { get; set; } = null;
|
||||
public bool? Shadow { get; set; } = null;
|
||||
public SaXlUnderlineStyle? Underline { get; set; } = null;
|
||||
}
|
||||
//=======================================================================
|
||||
public class SaMsExcelItemAttr : SaMsExcelFontAttr
|
||||
{
|
||||
// Item attributes.
|
||||
// Attributes that are changed from their default (generally null) are set against the specified range.
|
||||
/// <summary>Cell data format. "@"=Text etc.</summary>
|
||||
public String NumberFormat { get; set; } = String.Empty;
|
||||
/// <summary>Cell horizontal alignment. XlHAlign.xlHAlignLeft, xlHAlignCenter, xlHAlignRight etc.</summary>
|
||||
public short? HorizontalAlignment { get; set; } = null;
|
||||
/// <summary>Cell indentation. Tabbed - left, right or distributed alignment [0 to 6]</summary>
|
||||
public short? IndentLevel { get; set; } = null;
|
||||
/// <summary>Cell vertical alignment. XlVAlign.xlTop, xlCenter, xlBottom, xlJustify, xlDistributed etc.</summary>
|
||||
public short? VerticalAlignment { get; set; } = null;
|
||||
/// <summary>Whether to allow text to wrap in cells.</summary>
|
||||
public bool? WrapText { get; set; } = null;
|
||||
/// <summary>Whether cells are merged.</summary>
|
||||
public bool? MergeCells { get; set; } = null;
|
||||
/// <summary>Font colour index, ref. XlColorIndex. Black = 1 etc.</summary>
|
||||
public SaXlColourIndex InteriorColourIndex { get; set; } = SaXlColourIndex.NotSpecified;
|
||||
/// <summary>Cell RGB colour value, ref. XlRgbColor. Overrides colour index if changed from default value.</summary>
|
||||
public int? InteriorColour { get; set; } = null;
|
||||
/// <summary>Cell pattern, ref. XlPattern. xlSolid etc.</summary>
|
||||
public SaXlPattern InteriorPattern { get; set; } = SaXlPattern.NotSpecified;
|
||||
/// <summary>Cell pattern colour index, ref. XlColorIndex. xlAutomatic etc.</summary>
|
||||
public SaXlColourIndex InteriorPatternColourIndex { get; set; } = SaXlColourIndex.NotSpecified;
|
||||
/// <summary>Cell pattern RBG Colour value, ref. XlRgbColor. Overrides colour index if changed from default value.</summary>
|
||||
public int? InteriorPatternColour { get; set; } = null;
|
||||
// Borders.
|
||||
public SaMsExcelBorderAttr BorderLeft { get; } = new SaMsExcelBorderAttr(XlBordersIndex.xlEdgeLeft);
|
||||
public SaMsExcelBorderAttr BorderTop { get; } = new SaMsExcelBorderAttr(XlBordersIndex.xlEdgeTop);
|
||||
public SaMsExcelBorderAttr BorderRight { get; } = new SaMsExcelBorderAttr(XlBordersIndex.xlEdgeRight);
|
||||
public SaMsExcelBorderAttr BorderBottom { get; } = new SaMsExcelBorderAttr(XlBordersIndex.xlEdgeBottom);
|
||||
public SaMsExcelBorderAttr BorderInsideVertical { get; } = new SaMsExcelBorderAttr(XlBordersIndex.xlInsideVertical);
|
||||
public SaMsExcelBorderAttr BorderInsideHorizontal { get; } = new SaMsExcelBorderAttr(XlBordersIndex.xlInsideHorizontal);
|
||||
public List<SaMsExcelBorderAttr> Borders
|
||||
{
|
||||
get
|
||||
{
|
||||
List<SaMsExcelBorderAttr> borders = new List<SaMsExcelBorderAttr>();
|
||||
borders.Add(BorderLeft);
|
||||
borders.Add(BorderTop);
|
||||
borders.Add(BorderRight);
|
||||
borders.Add(BorderBottom);
|
||||
return borders;
|
||||
}
|
||||
}
|
||||
}
|
||||
//=======================================================================
|
||||
public abstract class SaMsSpreadsheet : SaErrorStateItem
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Definitions.
|
||||
public static int FontSizeMin { get; } = 4;
|
||||
public static int FontSizeMax { get; } = 48;
|
||||
public static int NullColour { get; } = 0x4a4d4120; /* AFX_RFX_LONG_PSEUDO_NULL */
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
protected SaMsSpreadsheet()
|
||||
{
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// W o r k b o o k
|
||||
//-------------------------------------------------------------------
|
||||
public abstract bool IsWorkbookValid();
|
||||
public abstract bool CreateWorkbook();
|
||||
public abstract bool OpenWorkbook(String filePath);
|
||||
public abstract bool SaveDocument(String filePath, int fileFormat = (int)SaXlFileFormat.Default /* Default: XlFileFormat.xlOpenXMLWorkbook */, bool bAutomaticallyOverwrite = false);
|
||||
public abstract bool CloseWorkbook();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// W o r k s h e e t
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Is the current worksheet valid.</summary>
|
||||
public abstract bool IsWorksheetValid();
|
||||
/// <summary>Number of worksheets in the workbook.</summary>
|
||||
public abstract uint WorksheetCount { get; }
|
||||
/// <summary>Set the worksheets in the workbook - sheets are added or removed to match the value.</summary>
|
||||
public abstract bool SetWorksheetCount(int worksheetCount);
|
||||
/// <summary>Add a worksheet to the workbook.</summary>
|
||||
public abstract bool AddWorksheet(String name);
|
||||
/// <summary>Remove the nth worksheet - position from 1.</summary>
|
||||
public abstract bool RemoveWorksheet(uint worksheetPos);
|
||||
/// <summary>Open the nth worksheet - position from 1.</summary>
|
||||
public abstract bool OpenWorksheet(uint worksheetPos);
|
||||
/// <summary>Get the position of the current worksheet. 0 = not open.</summary>
|
||||
public abstract uint WorksheetPos { get; }
|
||||
/// <summary>Get the name of the current worksheet.</summary>
|
||||
public abstract String WorksheetName { get; set; }
|
||||
/// <summary>Set the default attributes for the entire worksheet</summary>
|
||||
public abstract bool SetWorksheetAttr(SaMsExcelItemAttr attr);
|
||||
/// <summary>Close the current worksheet.</summary>
|
||||
public abstract bool CloseWorksheet();
|
||||
// Worksheet Page Setup.
|
||||
/// <summary>Configure the Page Setup properties.</summary>
|
||||
public abstract bool SetPageSetup(SaMsExcelPageSetup_Config pageSetupConfig);
|
||||
/// <summary>Configure a page break at the specified cell.</summary>
|
||||
public abstract bool SetPageBreak(uint colPos, uint rowPos);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// C o l u m n s
|
||||
//-------------------------------------------------------------------
|
||||
public abstract uint GetActiveColPos();
|
||||
public abstract double GetColWidth(uint colPos, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point);
|
||||
public abstract bool SetColWidth(uint colPos, double fWidth, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// R o w s
|
||||
//-------------------------------------------------------------------
|
||||
public abstract uint GetActiveRowPos();
|
||||
public abstract List<DataValue> GetRowDataValues(uint rowPos, int maxColumns = 0);
|
||||
public abstract double GetRowHeight(uint rowPos, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point);
|
||||
public abstract bool SetRowHeight(uint rowPos, double fHeight, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// C e l l s
|
||||
//-------------------------------------------------------------------
|
||||
public abstract void SetActiveCell(uint colPos, uint rowPos);
|
||||
public abstract String GetCellFormula(uint colPos, uint rowPos);
|
||||
public abstract DataValue GetCellDataValue(uint colPos, uint rowPos);
|
||||
public abstract bool SetCellFormula(uint colPos, uint rowPos, String value);
|
||||
public abstract bool SetCellFormula(uint colPos, uint rowPos, String value, SaMsExcelItemAttr attr);
|
||||
public abstract bool SetRowFormulas(uint colStart, uint row, List<Object> values);
|
||||
public abstract bool SetRangeFormulas(SaMsExcelRange range, List<Object> values);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Populate headings.
|
||||
public bool SetColumnHeadings(List<ColumnDfn> columns, SaMsExcelColumnHeading_Config config)
|
||||
{
|
||||
ClearErrorState();
|
||||
double columnWidthPixelsPerCm = Math.Min(100.0, Math.Max(10.0, config.ColumnWidthPixelsPerCm));
|
||||
uint firstHeadingRow = (uint)Math.Max(1, config.FirstHeadingRow);
|
||||
try
|
||||
{
|
||||
// Populate default heading cell attributes.
|
||||
SaMsExcelItemAttr attrHdrDefault = new SaMsExcelItemAttr();
|
||||
attrHdrDefault.Bold = config.HeadingTextBold;
|
||||
attrHdrDefault.FontSize = (short)Math.Min(80, Math.Max(2, (int)config.HeadingFontSize));
|
||||
attrHdrDefault.InteriorColourIndex = config.InteriorColourIndex;
|
||||
if (config.InteriorColour != null)
|
||||
attrHdrDefault.InteriorColour = config.InteriorColour;
|
||||
if (config.BorderWeight != SaXlBorderWeight.NotSpecified)
|
||||
{
|
||||
attrHdrDefault.BorderLeft.Weight = config.BorderWeight;
|
||||
attrHdrDefault.BorderTop.Weight = config.BorderWeight;
|
||||
attrHdrDefault.BorderRight.Weight = config.BorderWeight;
|
||||
attrHdrDefault.BorderBottom.Weight = config.BorderWeight;
|
||||
attrHdrDefault.BorderInsideVertical.Weight = config.BorderWeight;
|
||||
}
|
||||
SaMsExcelRange rangeHeadings = new SaMsExcelRange(config.FirstHeadingColumn, firstHeadingRow, (uint)(config.FirstHeadingColumn + columns.Count - 1), firstHeadingRow);
|
||||
SetRangeAttr(rangeHeadings, attrHdrDefault);
|
||||
|
||||
// Set default column attributes.
|
||||
bool defaultColumnAttributesPopulated = false;
|
||||
SaMsExcelItemAttr attrColDefault = new SaMsExcelItemAttr();
|
||||
if (config.SetColumnAlignment)
|
||||
{
|
||||
attrColDefault.HorizontalAlignment = (short)XlHAlign.xlHAlignLeft;
|
||||
defaultColumnAttributesPopulated = true;
|
||||
}
|
||||
if (config.SetColumnDataTypeFormat)
|
||||
{
|
||||
attrColDefault.NumberFormat = "@"; // '@' = 'Text' format.
|
||||
defaultColumnAttributesPopulated = true;
|
||||
}
|
||||
if (defaultColumnAttributesPopulated)
|
||||
{
|
||||
SaMsExcelRange rangeColumns = new SaMsExcelRange(config.FirstHeadingColumn, 0, (uint)(config.FirstHeadingColumn + columns.Count - 1), 0);
|
||||
SetRangeAttr(rangeColumns, attrColDefault);
|
||||
}
|
||||
|
||||
// Populate column headings and specific styles.
|
||||
List<Object> values = new List<Object>();
|
||||
for (int columnIdx = 0; columnIdx < columns.Count; columnIdx++)
|
||||
{
|
||||
ColumnDfn column = columns[columnIdx];
|
||||
uint col = (uint)(Math.Max(1, config.FirstHeadingColumn) + columnIdx);
|
||||
SaMsExcelRange range = new SaMsExcelRange(col, firstHeadingRow);
|
||||
|
||||
// Specific heading cell attributes - none supported as yet.
|
||||
bool headingCellHasSpecificAttr = false;
|
||||
SaMsExcelItemAttr attrHdr = new SaMsExcelItemAttr();
|
||||
if (headingCellHasSpecificAttr)
|
||||
SetRangeAttr(range, attrHdr);
|
||||
|
||||
// Column width and caption:
|
||||
if (config.SetColumnWidths) SetColWidth(col, column.Width / columnWidthPixelsPerCm, SaExcelLogicalUnit.Cm);
|
||||
values.Add(column.Caption);
|
||||
|
||||
// Column attributes:
|
||||
bool columnHasSpecificAttributes = false;
|
||||
SaMsExcelItemAttr attrCol = new SaMsExcelItemAttr();
|
||||
if (config.SetColumnAlignment && column.Alignment != ColumnAlignment.Left && column.Alignment != ColumnAlignment.Default)
|
||||
{
|
||||
columnHasSpecificAttributes = true;
|
||||
switch (column.Alignment)
|
||||
{
|
||||
case ColumnAlignment.Center: attrCol.HorizontalAlignment = (short)XlHAlign.xlHAlignCenter; break;
|
||||
case ColumnAlignment.Right: attrCol.HorizontalAlignment = (short)XlHAlign.xlHAlignRight; break;
|
||||
}
|
||||
}
|
||||
if (config.SetColumnDataTypeFormat && column.DataType != DataValue.DataType.String)
|
||||
{
|
||||
columnHasSpecificAttributes = true;
|
||||
if (column.DataType == DataValue.DataType.Long || column.DataType == DataValue.DataType.Double || column.DataType == DataValue.DataType.Decimal)
|
||||
{
|
||||
// Numeric format: "#,##0.00"
|
||||
String numberFormat = "0";
|
||||
if (column.NumThousands != '\0')
|
||||
{
|
||||
numberFormat = "###" + numberFormat;
|
||||
numberFormat = numberFormat.Insert(1, column.NumThousands.ToString()); // Ends up as '#,##0'.
|
||||
}
|
||||
if ((column.DataType == DataValue.DataType.Double || column.DataType == DataValue.DataType.Decimal) && column.NumDecimals > 0)
|
||||
numberFormat += "." + "0".PadRight(column.NumDecimals, '0');
|
||||
attrCol.NumberFormat = numberFormat + ";[Red]-" + numberFormat;
|
||||
}
|
||||
else if (column.DataType == DataValue.DataType.Date) attrCol.NumberFormat = config.CellFormatDate;
|
||||
else if (column.DataType == DataValue.DataType.Time) attrCol.NumberFormat = config.CellFormatTime;
|
||||
else if (column.DataType == DataValue.DataType.DateTime) attrCol.NumberFormat = config.CellFormatDate + config.CellFormatDateTimeDelim + config.CellFormatTime;
|
||||
}
|
||||
if (columnHasSpecificAttributes)
|
||||
SetRangeAttr(new SaMsExcelRange(col, 0), attrCol);
|
||||
// Freeze the window below if a colmn has been specified:
|
||||
if (config.FreezeColumn > 0) FreezePanes(config.FreezeColumn, firstHeadingRow + 1);
|
||||
}
|
||||
// Populate header captions.
|
||||
SetRowFormulas(config.FirstHeadingColumn, firstHeadingRow, values);
|
||||
// Set header row to wrap text:
|
||||
if (config.HeadingTextWrap)
|
||||
{
|
||||
SaMsExcelItemAttr attrRow = new SaMsExcelItemAttr();
|
||||
attrRow.WrapText = true;
|
||||
SetRangeAttr(new SaMsExcelRange(0, firstHeadingRow), attrRow);
|
||||
// Auto fit the header row (set height to fit text):
|
||||
AutoFit(new SaMsExcelRange(0, firstHeadingRow));
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("SetColumnHeadings", exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Cell attributes.
|
||||
public abstract bool SetRangeAttr(SaMsExcelRange range, SaMsExcelItemAttr attr);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Add image to sheet.
|
||||
public abstract bool InsertImage(SaMsExcelImage_Config imageConfig);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public abstract bool FreezePanes(uint colPos, uint rowPos);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public abstract bool AutoFit(SaMsExcelRange range);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public abstract bool SelectRange(SaMsExcelRange range);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Utilities.
|
||||
public static String GetRangeId(SaMsExcelRange range, bool fixedCols = false, bool fixedRows = false)
|
||||
{
|
||||
// Not fixed: "A9:AB34"
|
||||
// Fixed cols: "$A9:$AB34"
|
||||
// Fixed rows: "A$9:AB$34"
|
||||
// Fixed: "$A$9:$AB$34"
|
||||
return (fixedCols ? "$" : "") + GetColumnPrefix(range.ColFrom) + (fixedRows ? "$" : "") + GetRowSuffix(range.RowFrom) + ":" + (fixedCols ? "$" : "") + GetColumnPrefix(range.ColTo) + (fixedRows ? "$" : "") + GetRowSuffix(range.RowTo);
|
||||
}
|
||||
public static String GetColumnPrefix(uint colPos)
|
||||
{
|
||||
// 1=A,2=B,3=C...26=Z,27=AA,28=AB etc
|
||||
uint dividend = colPos;
|
||||
string columnName = String.Empty;
|
||||
uint modulo = 0;
|
||||
while (dividend > 0)
|
||||
{
|
||||
modulo = (dividend - 1) % 26;
|
||||
columnName = Convert.ToChar(65 + modulo).ToString() + columnName;
|
||||
dividend = (uint)((dividend - modulo) / 26);
|
||||
}
|
||||
return columnName;
|
||||
}
|
||||
public static int GetIndexForCol(String column)
|
||||
{
|
||||
// A=1,B=2,C=3...Z=26,AA=27 etc
|
||||
int col = (column[0] - 'A');
|
||||
if (column.Length > 1)
|
||||
col = (column[1] * 26) + column[0];
|
||||
return col;
|
||||
}
|
||||
public static String GetColumnId(uint colPos)
|
||||
{
|
||||
// To reference entire column: A:A,B:A,C:A...Z:Z,AA:AA etc
|
||||
return GetColumnPrefix(colPos) + ":" + GetColumnPrefix(colPos);
|
||||
}
|
||||
public static String GetRowSuffix(uint rowPos)
|
||||
{
|
||||
// 1,2,3...26,27,28 etc
|
||||
return (rowPos > 0 ? rowPos.ToString() : "");
|
||||
}
|
||||
public static String GetRowId(uint rowPos)
|
||||
{
|
||||
// To reference entire row: 1:1,2:2,3:3 etc
|
||||
return GetRowSuffix(rowPos) + ":" + GetRowSuffix(rowPos);
|
||||
}
|
||||
public static String GetCellId(uint colPos, uint rowPos)
|
||||
{
|
||||
return GetColumnPrefix(colPos) + GetRowSuffix(rowPos);
|
||||
}
|
||||
public static DateTime ExtractDate(String value)
|
||||
{
|
||||
DateTime date = DateTime.MinValue;
|
||||
// TODO SaMsSpreadsheet.ExtractDate
|
||||
return date;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// L e n g t h U n i t C o n v e r s i o n
|
||||
//-------------------------------------------------------------------
|
||||
// Points
|
||||
// - 72 per inch
|
||||
// EMU - English Metric Unit
|
||||
// - 914400 EMUs per inch
|
||||
// - EMU = inch * 914400
|
||||
// - EMU = pixel * 914400 / 96 (assuming 96 dpi)
|
||||
//-------------------------------------------------------------------
|
||||
public static double PointsPerInch { get; } = 72;
|
||||
public static double PixelsPerInch { get; } = 96;
|
||||
public static double CmsPerInch { get; } = 2.54f;
|
||||
public double ConvertLength(double fLength, SaExcelLogicalUnit eUnitFrom, SaExcelLogicalUnit eUnitTo, bool bVertical)
|
||||
{
|
||||
// Convert length to points:
|
||||
double fLengthPoints = fLength;
|
||||
if (eUnitFrom == SaExcelLogicalUnit.Pixel) fLengthPoints = PixelsToPoints(fLength, bVertical);
|
||||
else if (eUnitFrom == SaExcelLogicalUnit.Cm) fLengthPoints = CmsToPoints(fLength);
|
||||
else if (eUnitFrom == SaExcelLogicalUnit.Inch) fLengthPoints = InchesToPoints(fLength);
|
||||
// Convert points to target units:
|
||||
double fLengthTarget = fLengthPoints;
|
||||
if (eUnitTo == SaExcelLogicalUnit.Pixel) fLengthTarget = PointsToPixels(fLengthPoints, bVertical);
|
||||
else if (eUnitTo == SaExcelLogicalUnit.Cm) fLengthTarget = PointsToCms(fLengthPoints);
|
||||
else if (eUnitTo == SaExcelLogicalUnit.Inch) fLengthTarget = PointsToInches(fLengthPoints);
|
||||
return fLengthTarget;
|
||||
}
|
||||
public double ToPoints(double fLength, SaExcelLogicalUnit eUnitFrom, bool bVertical)
|
||||
{
|
||||
return ConvertLength(fLength, eUnitFrom, SaExcelLogicalUnit.Point, bVertical);
|
||||
}
|
||||
public double FromPoints(double fLength, SaExcelLogicalUnit eUnitTo, bool bVertical)
|
||||
{
|
||||
return ConvertLength(fLength, SaExcelLogicalUnit.Point, eUnitTo, bVertical);
|
||||
}
|
||||
public virtual double PointsToPixels(double points, bool bVertical)
|
||||
{
|
||||
// Pixel size depends on monitor resolution.
|
||||
// REf. https://stackoverflow.com/questions/139655/convert-pixels-to-points
|
||||
// Assume 96 pixels per inch.
|
||||
return points * PixelsPerInch / PointsPerInch;
|
||||
}
|
||||
public virtual double PointsToCms(double points)
|
||||
{
|
||||
return PointsToInches(points) * CmsPerInch;
|
||||
}
|
||||
public virtual double PointsToInches(double points)
|
||||
{
|
||||
return points / PointsPerInch;
|
||||
}
|
||||
public virtual double PixelsToPoints(double pixels, bool bVertical)
|
||||
{
|
||||
// Pixel size depends on monitor resolution.
|
||||
// REf. https://stackoverflow.com/questions/139655/convert-pixels-to-points
|
||||
// Assume 96 pixels per inch.
|
||||
return pixels / PixelsPerInch * PointsPerInch;
|
||||
}
|
||||
public virtual double CmsToPoints(double cms)
|
||||
{
|
||||
return InchesToPoints(cms / CmsPerInch);
|
||||
}
|
||||
public virtual double InchesToPoints(double inches)
|
||||
{
|
||||
return inches * PointsPerInch;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
protected void HandleException(String fn, Exception exc)
|
||||
{
|
||||
SaLogger.Error(GetType().Name + "." + fn + " " + ExceptionUtil.GetLogMessage(exc));
|
||||
SetErrorState("Problems were encountered interfacing to Excel - " + ExceptionUtil.GetErrorStateMessage(exc));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,909 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Sarand.Net.Standard.Proc.Xml;
|
||||
using Sarand.Net.Standard.Proc.Zip;
|
||||
|
||||
namespace Sarand.Net.Standard.Proc.Excel
|
||||
{
|
||||
//=======================================================================
|
||||
/// <summary>Style properties retrieved directly from spreadsheet xml data.</summary>
|
||||
public class SaMsExcelStyle
|
||||
{
|
||||
public SaMsExcelStyle () { }
|
||||
public int NumFmtId { get; set; }
|
||||
public int FontId { get; set; }
|
||||
public int FillId { get; set; }
|
||||
public int BorderId { get; set; }
|
||||
public int XfId { get; set; }
|
||||
public bool QuotePrefix { get; set; }
|
||||
public bool PivotButton { get; set; }
|
||||
public bool ApplyNumberFormat { get; set; }
|
||||
public bool ApplyFont { get; set; }
|
||||
public bool ApplyFill { get; set; }
|
||||
public bool ApplyBorder { get; set; }
|
||||
public bool ApplyAlignment { get; set; }
|
||||
public bool ApplyProtection { get; set; }
|
||||
public XlHAlign AlignHorizontal { get; set; }
|
||||
public XlVAlign AlignVertical { get; set; }
|
||||
public String NumFmtCode { get; set; } = "";
|
||||
};
|
||||
|
||||
//=======================================================================
|
||||
/// <summary>Excel spreadsheet read directly from xml data rather than via COM/Interop.</summary>
|
||||
public class SaMsSpreadsheet_Direct : SaMsSpreadsheet
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
internal class Workbook
|
||||
{
|
||||
internal SaMsZipArchive WorkbookArchive { get; set; }
|
||||
internal SaMsXmlDocument WorkbookDoc { get; set; }
|
||||
internal SaMsXmlDocument SharedStringsDoc { get; set; }
|
||||
internal SaMsXmlDocument StylesDoc { get; set; }
|
||||
internal uint WorksheetCount { get; set; }
|
||||
internal uint ActiveSheetPos { get; set; }
|
||||
internal bool IsValid () { return (WorkbookDoc != null && WorkbookDoc.GetRootElement() != null); }
|
||||
}
|
||||
private Workbook workbook;
|
||||
private class Worksheet
|
||||
{
|
||||
internal uint WorksheetPos { get; set; }
|
||||
internal uint WorksheetId { get; set; }
|
||||
internal String WorksheetArchivePath { get; set; }
|
||||
internal String WorksheetName { get; set; }
|
||||
internal SaMsXmlDocument WorksheetDoc { get; set; }
|
||||
internal uint ActiveColPos { get; set; }
|
||||
internal uint ActiveRowPos { get; set; }
|
||||
internal class NodesData
|
||||
{
|
||||
internal SaMsXmlElement Cols { get; set; }
|
||||
internal SaMsXmlElement ActiveCol { get; set; }
|
||||
internal SaMsXmlElement Rows { get; set; }
|
||||
internal SaMsXmlElement ActiveRow { get; set; }
|
||||
}
|
||||
internal NodesData Nodes { get; } = new NodesData();
|
||||
bool IsValid () { return (WorksheetDoc != null && WorksheetDoc.GetRootElement() != null); }
|
||||
|
||||
}
|
||||
private Worksheet worksheet;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaMsSpreadsheet_Direct () : base()
|
||||
{
|
||||
}
|
||||
protected override void Dispose (bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
CloseWorkbook();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// W o r k b o o k
|
||||
//-------------------------------------------------------------------
|
||||
public override bool IsWorkbookValid ()
|
||||
{
|
||||
return (workbook != null && workbook.IsValid());
|
||||
}
|
||||
public override bool CreateWorkbook ()
|
||||
{
|
||||
CloseWorkbook();
|
||||
ClearErrorState();
|
||||
|
||||
// Create new workbook.
|
||||
workbook = new Workbook();
|
||||
workbook.WorkbookArchive = new SaMsZipArchive();
|
||||
workbook.SharedStringsDoc = new SaMsXmlDocument();
|
||||
workbook.StylesDoc = new SaMsXmlDocument();
|
||||
|
||||
return SetErrorState("Creating workbook not supported");
|
||||
}
|
||||
public override bool OpenWorkbook (String filePath)
|
||||
{
|
||||
CloseWorkbook();
|
||||
ClearErrorState();
|
||||
if (!File.Exists(filePath))
|
||||
return SetErrorState("Workbook not found");
|
||||
List<String> validExtensions = new List<string>() { /*".xls",*/ ".xlsx", ".xlsb", ".zip" };
|
||||
String extension = Path.GetExtension(filePath);
|
||||
if (!validExtensions.ContainsCI(Path.GetExtension(filePath)))
|
||||
return SetErrorState("Invalid document type (expected xlsx/xlsb)");
|
||||
|
||||
try
|
||||
{
|
||||
// Open workbook document.
|
||||
workbook = new Workbook();
|
||||
workbook.WorkbookArchive = new SaMsZipArchive();
|
||||
if (workbook.WorkbookArchive.OpenArchive(filePath))
|
||||
{
|
||||
ExtractWorkbookElementsFromArchive();
|
||||
}
|
||||
else return SetErrorState("Failed to open document: " + workbook.WorkbookArchive.ErrorStateMessage);
|
||||
}
|
||||
catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
public bool OpenWorkbook (byte[] workbookData)
|
||||
{
|
||||
CloseWorkbook();
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
using (MemoryStream workbookStream = new MemoryStream(workbookData))
|
||||
{
|
||||
OpenWorkbook(workbookStream);
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
public bool OpenWorkbook (Stream workbookStream)
|
||||
{
|
||||
CloseWorkbook();
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
// From start of stream.
|
||||
workbookStream.Seek(0, SeekOrigin.Begin);
|
||||
// Open workbook document.
|
||||
workbook = new Workbook();
|
||||
workbook.WorkbookArchive = new SaMsZipArchive();
|
||||
if (workbook.WorkbookArchive.OpenArchive(workbookStream))
|
||||
{
|
||||
ExtractWorkbookElementsFromArchive();
|
||||
}
|
||||
else return SetErrorState("Failed to open document: " + workbook.WorkbookArchive.ErrorStateMessage);
|
||||
}
|
||||
catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
private bool ExtractWorkbookElementsFromArchive ()
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
// Extract the workbook data.
|
||||
using (MemoryStream workbookFile = workbook.WorkbookArchive.ExtractFileToStream("xl/workbook.xml"))
|
||||
{
|
||||
if (workbookFile == null) return SetErrorState("Failed to load workbook data");
|
||||
workbook.WorkbookDoc = new SaMsXmlDocument();
|
||||
if (workbook.WorkbookDoc.LoadXml(workbookFile))
|
||||
{
|
||||
// Workbook successfully opened.
|
||||
workbook.ActiveSheetPos = 1;
|
||||
// Shared strings:
|
||||
using (MemoryStream sharedStringsFile = workbook.WorkbookArchive.ExtractFileToStream("xl/sharedStrings.xml"))
|
||||
{
|
||||
if (sharedStringsFile != null)
|
||||
{
|
||||
workbook.SharedStringsDoc = new SaMsXmlDocument();
|
||||
workbook.SharedStringsDoc.LoadXml(sharedStringsFile);
|
||||
}
|
||||
}
|
||||
// Styles:
|
||||
using (MemoryStream stylesFile = workbook.WorkbookArchive.ExtractFileToStream("xl/styles.xml"))
|
||||
{
|
||||
if (stylesFile != null)
|
||||
{
|
||||
workbook.StylesDoc = new SaMsXmlDocument();
|
||||
workbook.StylesDoc.LoadXml(stylesFile);
|
||||
}
|
||||
}
|
||||
// Set worksheet count and open first worksheet.
|
||||
PopulateWorksheetCount();
|
||||
OpenWorksheet(1);
|
||||
}
|
||||
else return SetErrorState("Failed to read workbook data");
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
public override bool SaveDocument (String filePath, int fileFormat, bool bAutomaticallyOverwrite)
|
||||
{
|
||||
ClearErrorState();
|
||||
if (fileFormat == 0)
|
||||
fileFormat = (int)XlFileFormat.xlOpenXMLWorkbook;
|
||||
if (fileFormat != (int)XlFileFormat.xlOpenXMLWorkbook)
|
||||
SetErrorState("Unsupported file format: " + ((XlFileFormat)fileFormat).ToString());
|
||||
if (!HasErrorState() && !workbook.IsValid())
|
||||
SetErrorState("Workbook is not open");
|
||||
SetErrorState("Saving workbook not supported");
|
||||
return !HasErrorState();
|
||||
}
|
||||
public override bool CloseWorkbook ()
|
||||
{
|
||||
ClearErrorState();
|
||||
CloseWorksheet();
|
||||
|
||||
// Clear workbook.
|
||||
if (workbook != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (workbook.StylesDoc != null) workbook.StylesDoc.Dispose(); workbook.StylesDoc = null;
|
||||
if (workbook.SharedStringsDoc != null) workbook.SharedStringsDoc.Dispose(); workbook.SharedStringsDoc = null;
|
||||
if (workbook.WorkbookDoc != null) workbook.WorkbookDoc.Dispose(); workbook.WorkbookDoc = null;
|
||||
if (workbook.WorkbookArchive != null) workbook.WorkbookArchive.Dispose(); workbook.WorkbookArchive = null;
|
||||
}
|
||||
catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
workbook = null;
|
||||
}
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// W o r k s h e e t
|
||||
//-------------------------------------------------------------------
|
||||
public override bool IsWorksheetValid ()
|
||||
{
|
||||
return (worksheet != null && worksheet.WorksheetDoc != null);
|
||||
}
|
||||
public override uint WorksheetCount { get { return workbook.WorksheetCount; } }
|
||||
private void PopulateWorksheetCount ()
|
||||
{
|
||||
if (!IsWorkbookValid()) return;
|
||||
try
|
||||
{
|
||||
// Count worksheets in workbook.
|
||||
SaMsXmlElement nodeWorkbook = workbook.WorkbookDoc.GetRootElement();
|
||||
SaMsXmlElement nodeSheets = nodeWorkbook.GetFirstChildElement("sheets");
|
||||
workbook.WorksheetCount = (uint)nodeSheets.GetChildElements("sheet").Count;
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetWorksheetCount", exc); }
|
||||
}
|
||||
public override bool SetWorksheetCount (int worksheetCount)
|
||||
{
|
||||
ClearErrorState();
|
||||
return SetErrorState("Modifying workbook not supported");
|
||||
}
|
||||
public override bool AddWorksheet(String name)
|
||||
{
|
||||
return SetErrorState("Modifying workbook not supported");
|
||||
}
|
||||
public override bool RemoveWorksheet(uint worksheetPos)
|
||||
{
|
||||
return SetErrorState("Modifying workbook not supported");
|
||||
}
|
||||
public override bool OpenWorksheet (uint worksheetPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
if (!workbook.IsValid()) return SetErrorState("Workbook is not open");
|
||||
if (worksheetPos > WorksheetCount) return SetErrorState("Invalid sheet specified");
|
||||
if (worksheetPos <= 0) worksheetPos = Math.Max(1, workbook.ActiveSheetPos);
|
||||
CloseWorksheet();
|
||||
try
|
||||
{
|
||||
worksheet = new Worksheet();
|
||||
// Locate worksheet in workbook by 0-index.
|
||||
SaMsXmlElement workbookElement = workbook.WorkbookDoc.GetRootElement();
|
||||
SaMsXmlElement sheetsElement = workbookElement.GetFirstChildElement("sheets");
|
||||
long sheetCount = 0;
|
||||
foreach (SaMsXmlElement sheetElement in sheetsElement.GetChildElements("sheet"))
|
||||
{
|
||||
sheetCount++;
|
||||
if (sheetCount == worksheetPos)
|
||||
{
|
||||
// Extract the worksheet data.
|
||||
uint sheetId = (uint)StringUtil.ToInt(sheetElement.GetAttributeValue("sheetId"));
|
||||
String worksheetArchivePath = "xl/worksheets/sheet" + worksheetPos.ToString() + ".xml";
|
||||
using (MemoryStream worksheetFile = workbook.WorkbookArchive.ExtractFileToStream(worksheetArchivePath))
|
||||
{
|
||||
if (worksheetFile == null) return SetErrorState("Failed to load worksheet data");
|
||||
worksheet.WorksheetDoc = new SaMsXmlDocument();
|
||||
if (worksheet.WorksheetDoc.LoadXml(worksheetFile))
|
||||
{
|
||||
workbook.ActiveSheetPos = worksheetPos;
|
||||
worksheet.WorksheetPos = worksheetPos;
|
||||
worksheet.WorksheetId = sheetId;
|
||||
worksheet.WorksheetArchivePath = worksheetArchivePath;
|
||||
worksheet.WorksheetName = sheetElement.GetAttributeValue("name");
|
||||
worksheet.ActiveColPos = 1;
|
||||
worksheet.ActiveRowPos = 1;
|
||||
SaMsXmlElement nodeWorksheet = worksheet.WorksheetDoc.GetRootElement();
|
||||
worksheet.Nodes.Cols = nodeWorksheet.GetFirstChildElement("cols");
|
||||
worksheet.Nodes.ActiveCol = worksheet.Nodes.Cols.GetFirstChildElement("col");
|
||||
worksheet.Nodes.Rows = nodeWorksheet.GetFirstChildElement("sheetData");
|
||||
worksheet.Nodes.ActiveRow = worksheet.Nodes.Rows.GetFirstChildElement("row");
|
||||
workbook.ActiveSheetPos = worksheetPos;
|
||||
}
|
||||
else return SetErrorState("Failed to read data for worksheet " + worksheetPos.ToString());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (worksheet.WorksheetDoc == null) return SetErrorState("Unable to load worksheet " + worksheetPos.ToString());
|
||||
}
|
||||
catch (Exception exc) { HandleException("OpenWorksheet", exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
public override uint WorksheetPos { get { return workbook.ActiveSheetPos; } }
|
||||
public override String WorksheetName
|
||||
{
|
||||
get { return ""; }
|
||||
set { }
|
||||
}
|
||||
public override bool SetWorksheetAttr (SaMsExcelItemAttr attr)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
public override bool CloseWorksheet ()
|
||||
{
|
||||
ClearErrorState();
|
||||
|
||||
if (worksheet != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (worksheet.WorksheetDoc != null) worksheet.WorksheetDoc.Dispose(); worksheet.WorksheetDoc = null;
|
||||
if (worksheet.Nodes.Cols != null) worksheet.Nodes.Cols.Dispose(); worksheet.Nodes.Cols = null;
|
||||
if (worksheet.Nodes.ActiveCol != null) worksheet.Nodes.ActiveCol.Dispose(); worksheet.Nodes.ActiveCol = null;
|
||||
if (worksheet.Nodes.Rows != null) worksheet.Nodes.Rows.Dispose(); worksheet.Nodes.Rows = null;
|
||||
if (worksheet.Nodes.ActiveRow != null) worksheet.Nodes.ActiveRow.Dispose(); worksheet.Nodes.ActiveRow = null;
|
||||
}
|
||||
catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
worksheet = null;
|
||||
}
|
||||
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Worksheet Page Setup.
|
||||
public override bool SetPageSetup (SaMsExcelPageSetup_Config pageSetupConfig)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
public override bool SetPageBreak (uint col, uint row)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// C o l u m n s
|
||||
//-------------------------------------------------------------------
|
||||
public override uint GetActiveColPos ()
|
||||
{
|
||||
return worksheet.ActiveColPos;
|
||||
}
|
||||
private SaMsXmlElement GetColElement (uint colPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
if (worksheet.ActiveColPos == colPos) return worksheet.Nodes.ActiveCol;
|
||||
int colCount = 0;
|
||||
foreach (SaMsXmlElement colElement in worksheet.Nodes.Cols.GetChildElements("Col"))
|
||||
{
|
||||
if (++colCount == colPos)
|
||||
{
|
||||
if (worksheet.Nodes.ActiveCol != null) worksheet.Nodes.ActiveCol.Dispose();
|
||||
worksheet.ActiveColPos = colPos;
|
||||
worksheet.Nodes.ActiveCol = colElement;
|
||||
return colElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetColElement", exc); }
|
||||
return new SaMsXmlElement(null);
|
||||
}
|
||||
public override double GetColWidth (uint colPos, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
// Retrieve width (in points) from column.
|
||||
SaMsXmlNode nodeCol = GetColElement(colPos);
|
||||
double width = nodeCol.GetAttributeValue("width").ToDouble();
|
||||
// Adjust for units.
|
||||
if (unit == SaExcelLogicalUnit.Pixel) return PointsToPixels(width, false);
|
||||
if (unit == SaExcelLogicalUnit.Cm) return PointsToCms(width);
|
||||
if (unit == SaExcelLogicalUnit.Inch) return PointsToInches(width);
|
||||
return width;
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetColWidth", exc); }
|
||||
return 0.0;
|
||||
}
|
||||
public override bool SetColWidth (uint colPos, double fWidth, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// R o w s
|
||||
//-------------------------------------------------------------------
|
||||
public override uint GetActiveRowPos ()
|
||||
{
|
||||
return worksheet.ActiveRowPos;
|
||||
}
|
||||
SaMsXmlElement GetRowElement (uint rowPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
if (worksheet.ActiveRowPos == rowPos) return worksheet.Nodes.ActiveRow;
|
||||
foreach (SaMsXmlElement rowElement in worksheet.Nodes.Rows.GetChildElements("row"))
|
||||
{
|
||||
if (rowElement.GetAttributeValue("r").ToLong() == rowPos)
|
||||
{
|
||||
if (worksheet.Nodes.ActiveRow != null) worksheet.Nodes.ActiveRow.Dispose();
|
||||
worksheet.ActiveRowPos = rowPos;
|
||||
worksheet.Nodes.ActiveRow = rowElement;
|
||||
return rowElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetRowElement", exc); }
|
||||
return new SaMsXmlElement(null);
|
||||
}
|
||||
public override double GetRowHeight (uint rowPos, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
// Retrieve height (in points) from row.
|
||||
SaMsXmlElement rowElement = GetRowElement(rowPos);
|
||||
double height = rowElement.GetAttributeValue("ht").ToDouble();
|
||||
// Adjust for units.
|
||||
if (unit == SaExcelLogicalUnit.Pixel) return PointsToPixels(height, true);
|
||||
if (unit == SaExcelLogicalUnit.Cm) return PointsToCms(height);
|
||||
if (unit == SaExcelLogicalUnit.Inch) return PointsToInches(height);
|
||||
return height;
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetRowHeight", exc); }
|
||||
return 0.0;
|
||||
}
|
||||
public override bool SetRowHeight (uint rowPos, double fHeight, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// R o w s
|
||||
//-------------------------------------------------------------------
|
||||
public override List<DataValue> GetRowDataValues (uint rowPos, int maxColumns = 0)
|
||||
{
|
||||
ClearErrorState();
|
||||
List<DataValue> values = new List<DataValue>();
|
||||
try
|
||||
{
|
||||
SaMsXmlElement rowElement = GetRowElement(rowPos);
|
||||
foreach (SaMsXmlElement cellElement in rowElement.GetChildElements("c"))
|
||||
{
|
||||
// CellId may be needed in case cells are skipped in the data.
|
||||
// Doesn't appear to be the case, even when previous cell is merged with next.
|
||||
String cellId = cellElement.GetAttributeValue("r");
|
||||
values.Add(GetCellDataValue(cellElement));
|
||||
if (maxColumns > 0 && values.Count >= maxColumns) break;
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetRowDataValues", exc); }
|
||||
return values;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// C e l l s
|
||||
//-------------------------------------------------------------------
|
||||
SaMsXmlElement GetCellElement (uint colPos, uint rowPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
String cellId = GetCellId(colPos,rowPos);
|
||||
try
|
||||
{
|
||||
SaMsXmlElement rowElement = GetRowElement(rowPos);
|
||||
foreach (SaMsXmlElement cellElement in rowElement.GetChildElements("c"))
|
||||
{
|
||||
if (cellElement.GetAttributeValue("r").EqualsCI(cellId))
|
||||
return cellElement;
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetCellElement", exc); }
|
||||
return new SaMsXmlElement(null);
|
||||
}
|
||||
public override void SetActiveCell (uint colPos, uint rowPos)
|
||||
{
|
||||
// ToDo SetActiveCell.
|
||||
SetErrorState("Not supported");
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
private bool IsCellFormula (uint colPos, uint rowPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
bool bIsFormula = false;
|
||||
try
|
||||
{
|
||||
SaMsXmlElement cellElement = GetCellElement(colPos,rowPos);
|
||||
bIsFormula = !cellElement.GetAttributeValue("f").IsEmpty();
|
||||
}
|
||||
catch (Exception exc) { HandleException("IsCellFormula", exc); }
|
||||
return bIsFormula;
|
||||
}
|
||||
private bool IsCellNumeric (uint colPos, uint rowPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
SaMsXmlElement cellElement = GetCellElement(colPos,rowPos);
|
||||
SaMsExcelStyle cellStyle = GetCellStyle(cellElement);
|
||||
return IsCellNumeric(cellElement, cellStyle);
|
||||
}
|
||||
catch (Exception exc) { HandleException("IsCellNumeric", exc); }
|
||||
return false;
|
||||
}
|
||||
private bool IsCellNumeric (SaMsXmlElement cellElement)
|
||||
{
|
||||
ClearErrorState();
|
||||
SaMsExcelStyle cellStyle = GetCellStyle(cellElement);
|
||||
return IsCellNumeric(cellElement, cellStyle);
|
||||
}
|
||||
private bool IsCellNumeric (SaMsXmlElement cellElement, SaMsExcelStyle cellStyle)
|
||||
{
|
||||
ClearErrorState();
|
||||
return (cellElement.GetAttributeValue("t").IsEmpty() && !IsDateTimeStyle(cellStyle.NumFmtCode));
|
||||
}
|
||||
private bool IsCellDate (uint colPos, uint rowPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
bool bIsDate = false;
|
||||
try
|
||||
{
|
||||
SaMsXmlElement cellElement = GetCellElement(colPos,rowPos);
|
||||
SaMsExcelStyle cellStyle = GetCellStyle(cellElement);
|
||||
return IsCellDate(cellElement, cellStyle);
|
||||
}
|
||||
catch (Exception exc) { HandleException("IsCellDate", exc); }
|
||||
return bIsDate;
|
||||
}
|
||||
private bool IsCellDate (SaMsXmlElement cellElement)
|
||||
{
|
||||
return IsCellDate(cellElement, GetCellStyle(cellElement));
|
||||
}
|
||||
private bool IsCellDate (SaMsXmlElement cellElement, SaMsExcelStyle cellStyle)
|
||||
{
|
||||
ClearErrorState();
|
||||
return IsDateTimeStyle(cellStyle.NumFmtCode);
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
public override String GetCellFormula (uint colPos, uint rowPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
SaMsXmlElement cellElement = GetCellElement(colPos,rowPos);
|
||||
String formula = cellElement.GetAttributeValue("f");
|
||||
if (formula.IsEmpty())
|
||||
formula = GetCellText(cellElement, true);
|
||||
return formula;
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetCellFormula", exc); }
|
||||
return "";
|
||||
}
|
||||
private String GetCellText (SaMsXmlElement cellElement, bool trimValue = true)
|
||||
{
|
||||
ClearErrorState();
|
||||
String value = "";
|
||||
try
|
||||
{
|
||||
if (cellElement.GetAttributeValue("t").EqualsCI("s"))
|
||||
value = GetSharedString(cellElement);
|
||||
else
|
||||
value = cellElement.GetChildText("v");
|
||||
if (trimValue) value.TrimAll();
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetCellText", exc); }
|
||||
return value;
|
||||
}
|
||||
public override DataValue GetCellDataValue (uint colPos, uint rowPos)
|
||||
{
|
||||
return GetCellDataValue(GetCellElement(colPos, rowPos), false);
|
||||
}
|
||||
private DataValue GetCellDataValue (SaMsXmlElement cellElement, bool trimTextValue = true)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
SaMsExcelStyle cellStyle = GetCellStyle(cellElement);
|
||||
if (cellElement.GetAttributeValue("t").EqualsCI("s"))
|
||||
{
|
||||
String value = GetSharedString(cellElement);
|
||||
if (trimTextValue) value = value.TrimAll();
|
||||
return new DataValue(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
String value = cellElement.GetChildText("v");
|
||||
if (IsDateTimeStyle(cellStyle.NumFmtCode))
|
||||
return new DataValue(DateTime.FromOADate(value.ToDouble()));
|
||||
if (IsCellNumeric(cellElement, cellStyle))
|
||||
{
|
||||
if (value.IsNumeric())
|
||||
return new DataValue(value.ToLong());
|
||||
if (value.IsDecimal())
|
||||
{
|
||||
#if DEBUG
|
||||
//if (StringUtil.ToInt(value) > 600) Debugger.Break();
|
||||
#endif
|
||||
return new DataValue(value.ToDecimal());
|
||||
}
|
||||
}
|
||||
if (trimTextValue) value = value.TrimAll();
|
||||
return new DataValue(value);
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetCellDataValue", exc); }
|
||||
return new DataValue();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
// Shared string for cell.
|
||||
private String GetSharedString (SaMsXmlElement nodeElement)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
SaMsXmlElement sharedStringElement = GetSharedStringElement(nodeElement);
|
||||
return sharedStringElement.GetChildText("t");
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetSharedString", exc); }
|
||||
return "";
|
||||
}
|
||||
private SaMsXmlElement GetSharedStringElement (SaMsXmlElement cellElement)
|
||||
{
|
||||
ClearErrorState();
|
||||
if (workbook.SharedStringsDoc == null || cellElement == null || !cellElement.Valid) return null;
|
||||
if (!cellElement.GetAttributeValue("t").EqualsCI("s") || !cellElement.GetChildText("v").IsNumeric()) return null;
|
||||
// Shared strings are indexed from 0.
|
||||
long sharedStringIdx = -1;
|
||||
try
|
||||
{
|
||||
long iIdx = cellElement.GetChildText("v").ToLong();
|
||||
SaMsXmlElement sstElement = workbook.SharedStringsDoc.GetRootElement();
|
||||
foreach (SaMsXmlElement siElement in sstElement.GetChildElements("si"))
|
||||
{
|
||||
if (++sharedStringIdx == iIdx)
|
||||
return siElement;
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetSharedStringNode", exc); }
|
||||
return new SaMsXmlElement(null);
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
public override bool SetCellFormula (uint colPos, uint rowPos, String value)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
public override bool SetCellFormula (uint colPos, uint rowPos, String value, SaMsExcelItemAttr attr)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
public override bool SetRowFormulas (uint colPosStart, uint rowPos, List<Object> values)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
public override bool SetRangeFormulas (SaMsExcelRange range, List<Object> values)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// C e l l S t y l e
|
||||
//-------------------------------------------------------------------
|
||||
private String GetBuiltInStyleFormat (int numFmtId)
|
||||
{
|
||||
// Ref. http://stackoverflow.com/questions/4730152/what-indicates-an-office-open-xml-cell-contains-a-date-time-value
|
||||
switch (numFmtId)
|
||||
{
|
||||
//
|
||||
case 0: return "General";
|
||||
case 1: return "0";
|
||||
case 2: return "0.00";
|
||||
case 3: return "#,##0";
|
||||
case 4: return "#,##0.00";
|
||||
//
|
||||
case 9: return "0%";
|
||||
case 10: return "0.00%";
|
||||
case 11: return "0.00E+00";
|
||||
case 12: return "# ?/?";
|
||||
case 13: return "# ??/??";
|
||||
case 14: return "mm-dd-yy";
|
||||
case 15: return "d-mmm-yy";
|
||||
case 16: return "d-mmm";
|
||||
case 17: return "mmm-yy";
|
||||
case 18: return "h:mm AM/PM";
|
||||
case 19: return "h:mm:ss AM/PM";
|
||||
case 20: return "h:mm";
|
||||
case 21: return "h:mm:ss";
|
||||
case 22: return "m/d/yy h:mm";
|
||||
//
|
||||
case 37: return "#,##0 ;(#,##0)";
|
||||
case 38: return "#,##0 ;[Red](#,##0)";
|
||||
case 39: return "#,##0.00;(#,##0.00)";
|
||||
case 40: return "#,##0.00;[Red](#,##0.00)";
|
||||
//
|
||||
case 44: return "_(\"$\"* #,##0.00_);_(\"$\"* \\(#,##0.00\\);_(\"$\"* \"-\"??_);_(@_)";
|
||||
case 45: return "mm:ss";
|
||||
case 46: return "[h]:mm:ss";
|
||||
case 47: return "mmss.0";
|
||||
case 48: return "##0.0E+0";
|
||||
case 49: return "@";
|
||||
//
|
||||
case 27: return "[$-404]e/m/d";
|
||||
case 30: return "m/d/yy";
|
||||
case 36: return "[$-404]e/m/d";
|
||||
case 50: return "[$-404]e/m/d";
|
||||
case 57: return "[$-404]e/m/d";
|
||||
//
|
||||
case 59: return "t0";
|
||||
case 60: return "t0.00";
|
||||
case 61: return "t#,##0";
|
||||
case 62: return "t#,##0.00";
|
||||
case 67: return "t0%";
|
||||
case 68: return "t0.00%";
|
||||
case 69: return "t# ?/?";
|
||||
case 70: return "t# ??/??";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
private SaMsExcelStyle GetCellStyle (SaMsXmlElement cellElement)
|
||||
{
|
||||
ClearErrorState();
|
||||
SaMsExcelStyle style = new SaMsExcelStyle();
|
||||
if (workbook.SharedStringsDoc == null || cellElement == null || !cellElement.Valid || !cellElement.GetAttributeValue("s").IsNumeric()) return style;
|
||||
// Styles are indexed from 0.
|
||||
long styleIdx = -1;
|
||||
try
|
||||
{
|
||||
long cellStyleIdx = cellElement.GetAttributeValue("s").ToLong();
|
||||
SaMsXmlElement styleSheetElement = workbook.SharedStringsDoc.GetRootElement();
|
||||
SaMsXmlElement cellXfsElement = styleSheetElement.GetFirstChildElement("cellXfs");
|
||||
foreach (SaMsXmlElement xfElement in styleSheetElement.GetChildElements("xf"))
|
||||
{
|
||||
if (++styleIdx == cellStyleIdx)
|
||||
{
|
||||
// Construct style.
|
||||
style.NumFmtId = (int)xfElement.GetAttributeValue("numFmtId").ToLong();
|
||||
style.FontId = (int)xfElement.GetAttributeValue("fontId").ToLong();
|
||||
style.FillId = (int)xfElement.GetAttributeValue("fillId").ToLong();
|
||||
style.BorderId = (int)xfElement.GetAttributeValue("borderId").ToLong();
|
||||
style.XfId = (int)xfElement.GetAttributeValue("xfId").ToLong();
|
||||
style.QuotePrefix = xfElement.GetAttributeValue("quotePrefix").ToBool();
|
||||
style.PivotButton = xfElement.GetAttributeValue("pivotButton").ToBool();
|
||||
style.ApplyNumberFormat = xfElement.GetAttributeValue("applyNumberFormat").ToBool();
|
||||
style.ApplyFont = xfElement.GetAttributeValue("applyFont").ToBool();
|
||||
style.ApplyFill = xfElement.GetAttributeValue("applyFill").ToBool();
|
||||
style.ApplyBorder = xfElement.GetAttributeValue("applyBorder").ToBool();
|
||||
style.ApplyAlignment = xfElement.GetAttributeValue("applyAlignment").ToBool();
|
||||
style.ApplyProtection = xfElement.GetAttributeValue("applyProtection").ToBool();
|
||||
// Alignment.
|
||||
SaMsXmlNode nodeAlignment = xfElement.GetFirstChildElement("alignment");
|
||||
String sAlignHorizontal = nodeAlignment.GetAttributeValue("horizontal");
|
||||
if (sAlignHorizontal.EqualsCI("center")) style.AlignHorizontal = XlHAlign.xlHAlignCenter;
|
||||
else if (sAlignHorizontal.EqualsCI("centerContinuous")) style.AlignHorizontal = XlHAlign.xlHAlignCenterAcrossSelection;
|
||||
else if (sAlignHorizontal.EqualsCI("distributed")) style.AlignHorizontal = XlHAlign.xlHAlignDistributed;
|
||||
else if (sAlignHorizontal.EqualsCI("fill")) style.AlignHorizontal = XlHAlign.xlHAlignFill;
|
||||
else if (sAlignHorizontal.EqualsCI("justify")) style.AlignHorizontal = XlHAlign.xlHAlignJustify;
|
||||
else if (sAlignHorizontal.EqualsCI("left")) style.AlignHorizontal = XlHAlign.xlHAlignLeft;
|
||||
else if (sAlignHorizontal.EqualsCI("right")) style.AlignHorizontal = XlHAlign.xlHAlignRight;
|
||||
String sAlignVertical = nodeAlignment.GetAttributeValue("vertical");
|
||||
if (sAlignVertical.EqualsCI("center")) style.AlignVertical = XlVAlign.xlVAlignCenter;
|
||||
else if (sAlignVertical.EqualsCI("top")) style.AlignVertical = XlVAlign.xlVAlignTop;
|
||||
else if (sAlignVertical.EqualsCI("bottom")) style.AlignVertical = XlVAlign.xlVAlignBottom;
|
||||
else if (sAlignVertical.EqualsCI("distributed")) style.AlignVertical = XlVAlign.xlVAlignDistributed;
|
||||
else if (sAlignVertical.EqualsCI("justify")) style.AlignVertical = XlVAlign.xlVAlignJustify;
|
||||
// Number format.
|
||||
if (style.ApplyNumberFormat)
|
||||
{
|
||||
if (style.NumFmtId >= 164)
|
||||
{
|
||||
SaMsXmlElement numFmtsElement = styleSheetElement.GetFirstChildElement("NumFmts");
|
||||
foreach (SaMsXmlElement numFmtElement in numFmtsElement.GetChildElements("numFmt"))
|
||||
{
|
||||
if (numFmtElement.GetAttributeValue("numFmtId").ToLong() == style.NumFmtId)
|
||||
{
|
||||
style.NumFmtCode = numFmtElement.GetAttributeValue("formatCode");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else style.NumFmtCode = GetBuiltInStyleFormat(style.NumFmtId);
|
||||
}
|
||||
// Font.
|
||||
if (style.ApplyFont)
|
||||
{
|
||||
}
|
||||
// Fill.
|
||||
if (style.ApplyFill)
|
||||
{
|
||||
}
|
||||
// Borders.
|
||||
if (style.ApplyBorder)
|
||||
{
|
||||
}
|
||||
// Alignment.
|
||||
if (style.ApplyAlignment)
|
||||
{
|
||||
}
|
||||
// Protection.
|
||||
if (style.ApplyProtection)
|
||||
{
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetStyleNode", exc); }
|
||||
return style;
|
||||
}
|
||||
private bool IsDateStyle (String numFormat)
|
||||
{
|
||||
// Ref. http://stackoverflow.com/questions/19034805/how-to-distinguish-inline-numbers-from-ole-automation-date-numbers-in-openxml-sp/19582685#19582685
|
||||
if (IsTimeStyle(numFormat)) return false;
|
||||
if (numFormat.Contains("d")) return true;
|
||||
if (numFormat.Contains("m")) return true;
|
||||
if (numFormat.Contains("y")) return true;
|
||||
return false;
|
||||
}
|
||||
private bool IsTimeStyle (String numFormat)
|
||||
{
|
||||
if (numFormat.Contains("h")) return true;
|
||||
if (numFormat.Contains(":mm")) return true;
|
||||
if (numFormat.Contains("mm:")) return true;
|
||||
if (numFormat.Contains(":ss")) return true;
|
||||
return false;
|
||||
}
|
||||
private bool IsDateTimeStyle (String numFormat)
|
||||
{
|
||||
return (IsDateStyle(numFormat) || IsTimeStyle(numFormat));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Cell attributes.
|
||||
public override bool SetRangeAttr (SaMsExcelRange range, SaMsExcelItemAttr attr)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Add image to sheet.
|
||||
public override bool InsertImage (SaMsExcelImage_Config imageConfig)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override bool FreezePanes (uint colPos, uint rowPos)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override bool AutoFit (SaMsExcelRange range)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override bool SelectRange (SaMsExcelRange range)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,656 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using DocumentFormat.OpenXml;
|
||||
using DocumentFormat.OpenXml.Packaging;
|
||||
using DocumentFormat.OpenXml.Spreadsheet;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
|
||||
namespace Sarand.Net.Standard.Proc.Excel
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaMsSpreadsheet_OpenXml : SaMsSpreadsheet
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private class WorkbookData
|
||||
{
|
||||
public SpreadsheetDocument Document { get; set; }
|
||||
public MemoryStream MemoryStream { get; set; }
|
||||
public WorkbookPart WorkbookPart { get { return Document.WorkbookPart; } }
|
||||
}
|
||||
private WorkbookData workbook;
|
||||
private class WorksheetData
|
||||
{
|
||||
public WorksheetData(uint worksheetPos, WorksheetPart worksheetPart, Sheet sheet)
|
||||
{
|
||||
WorksheetPos = worksheetPos;
|
||||
WorksheetPart = worksheetPart;
|
||||
Sheet = sheet;
|
||||
}
|
||||
public uint WorksheetPos { get; }
|
||||
public WorksheetPart WorksheetPart { get; }
|
||||
public Sheet Sheet { get; }
|
||||
public SheetData SheetData { get { return WorksheetPart.Worksheet.GetFirstChild<SheetData>(); } }
|
||||
// Active column.
|
||||
public uint ActiveColumnPos { get; private set; }
|
||||
public Column ActiveColumn { get; private set; }
|
||||
public void SetActiveColumn(uint activeColumnPos, Column activeColumn)
|
||||
{
|
||||
ActiveColumnPos = activeColumnPos;
|
||||
ActiveColumn = activeColumn;
|
||||
}
|
||||
public void ClearActiveColumn()
|
||||
{
|
||||
ActiveColumnPos = 0;
|
||||
ActiveColumn = null;
|
||||
}
|
||||
// Active row.
|
||||
public uint ActiveRowPos { get; private set; }
|
||||
public Row ActiveRow { get; private set; }
|
||||
public void SetActiveRow(uint activeRowPos, Row activeRow)
|
||||
{
|
||||
ActiveRowPos = activeRowPos;
|
||||
ActiveRow = activeRow;
|
||||
}
|
||||
public void ClearActiveRow()
|
||||
{
|
||||
ActiveRowPos = 0;
|
||||
ActiveRow = null;
|
||||
}
|
||||
}
|
||||
private WorksheetData worksheet;
|
||||
private uint activeWorksheetPos;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaMsSpreadsheet_OpenXml() : base()
|
||||
{
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
CloseWorkbook();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
private WorkbookPart WorkbookPart { get { return workbook.WorkbookPart; } }
|
||||
private Sheets Sheets { get { return WorkbookPart.Workbook.Sheets; } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// W o r k b o o k
|
||||
//-------------------------------------------------------------------
|
||||
public override bool IsWorkbookValid()
|
||||
{
|
||||
return (workbook != null);
|
||||
}
|
||||
public override bool CreateWorkbook()
|
||||
{
|
||||
ClearErrorState();
|
||||
CloseWorkbook();
|
||||
try
|
||||
{
|
||||
workbook = new WorkbookData();
|
||||
workbook.MemoryStream = new MemoryStream();
|
||||
workbook.Document = SpreadsheetDocument.Create(workbook.MemoryStream, SpreadsheetDocumentType.Workbook);
|
||||
}
|
||||
catch (Exception exc) { SaLogger.Warn(exc.GetType().Name + ".CreateWorkbook " + ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return (workbook != null);
|
||||
}
|
||||
public override bool OpenWorkbook(String filePath)
|
||||
{
|
||||
ClearErrorState();
|
||||
CloseWorkbook();
|
||||
try
|
||||
{
|
||||
workbook = new WorkbookData();
|
||||
workbook.Document = SpreadsheetDocument.Create(filePath, SpreadsheetDocumentType.Workbook);
|
||||
}
|
||||
catch (Exception exc) { SaLogger.Warn(exc.GetType().Name + ".OpenWorkbook " + ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return (workbook != null);
|
||||
}
|
||||
public override bool SaveDocument(String filePath, int fileFormat, bool bAutomaticallyOverwrite)
|
||||
{
|
||||
ClearErrorState();
|
||||
|
||||
#pragma warning disable CS0219 // Variable is assigned but its value is never used
|
||||
SpreadsheetDocumentType documentType = SpreadsheetDocumentType.Workbook;
|
||||
#pragma warning restore CS0219 // Variable is assigned but its value is never used
|
||||
if (fileFormat == (int)XlFileFormat.xlOpenXMLTemplate || fileFormat == (int)XlFileFormat.xlTemplate || fileFormat == (int)XlFileFormat.xlTemplate8)
|
||||
documentType = SpreadsheetDocumentType.Template;
|
||||
else if (fileFormat == (int)XlFileFormat.xlOpenXMLWorkbookMacroEnabled)
|
||||
documentType = SpreadsheetDocumentType.MacroEnabledWorkbook;
|
||||
else if (fileFormat == (int)XlFileFormat.xlOpenXMLTemplateMacroEnabled)
|
||||
documentType = SpreadsheetDocumentType.MacroEnabledTemplate;
|
||||
else if (fileFormat == (int)XlFileFormat.xlOpenXMLAddIn || fileFormat == (int)XlFileFormat.xlAddIn || fileFormat == (int)XlFileFormat.xlAddIn8 || fileFormat == (int)XlFileFormat.xlIntlAddIn)
|
||||
documentType = SpreadsheetDocumentType.AddIn;
|
||||
|
||||
// ToDo Save OpenXML Excel document.
|
||||
|
||||
return !HasErrorState();
|
||||
}
|
||||
public override bool CloseWorkbook()
|
||||
{
|
||||
ClearErrorState();
|
||||
CloseWorksheet();
|
||||
try
|
||||
{
|
||||
if (workbook != null)
|
||||
{
|
||||
if (workbook.Document != null) workbook.Document.Dispose();
|
||||
if (workbook.MemoryStream != null) workbook.MemoryStream.Dispose();
|
||||
workbook = null;
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { SaLogger.Warn(exc.GetType().Name + ".CloseWorkbook " + ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
workbook = null;
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// W o r k s h e e t
|
||||
//-------------------------------------------------------------------
|
||||
public override bool IsWorksheetValid()
|
||||
{
|
||||
return (worksheet != null);
|
||||
}
|
||||
public override uint WorksheetCount
|
||||
{
|
||||
get
|
||||
{
|
||||
uint worksheetCount = 0;
|
||||
foreach (Sheet sheet in Sheets)
|
||||
worksheetCount++;
|
||||
return worksheetCount;
|
||||
}
|
||||
}
|
||||
public override bool SetWorksheetCount(int worksheetCount)
|
||||
{
|
||||
ClearErrorState();
|
||||
if (worksheetCount > 0 && worksheetCount < 11)
|
||||
{
|
||||
while (WorksheetCount < worksheetCount)
|
||||
AddWorksheet("");
|
||||
while (WorksheetCount > worksheetCount)
|
||||
RemoveWorksheet(WorksheetCount);
|
||||
OpenWorksheet(1);
|
||||
}
|
||||
else SetErrorState("SetWorksheetCount - Requested number of worksheets (" + worksheetCount.ToString() + ") must be between 1 and 10");
|
||||
return !HasErrorState();
|
||||
}
|
||||
public override bool AddWorksheet(String sheetName)
|
||||
{
|
||||
ClearErrorState();
|
||||
CloseWorksheet();
|
||||
|
||||
// Add a blank WorksheetPart.
|
||||
WorksheetPart worksheetPart = WorkbookPart.AddNewPart<WorksheetPart>();
|
||||
worksheetPart.Worksheet = new Worksheet(new SheetData());
|
||||
|
||||
// Get a unique ID for the new worksheet.
|
||||
Sheets sheets = WorkbookPart.Workbook.GetFirstChild<Sheets>();
|
||||
uint sheetId = 1;
|
||||
if (sheets.Elements<Sheet>().Count() > 0)
|
||||
{
|
||||
sheetId = sheets.Elements<Sheet>().Select(item => item.SheetId.Value).Max() + 1;
|
||||
}
|
||||
|
||||
// Append the new worksheet and associate it with the workbook.
|
||||
String relationshipId = WorkbookPart.GetIdOfPart(worksheetPart);
|
||||
sheetName = StringUtil.OnEmpty(StringUtil.TrimAll(sheetName), "Sheet" + sheetId);
|
||||
Sheet sheet = new Sheet() { Id = relationshipId, SheetId = sheetId, Name = sheetName };
|
||||
sheets.Append(sheet);
|
||||
|
||||
worksheet = new WorksheetData(WorksheetCount, worksheetPart, sheet);
|
||||
|
||||
return (worksheet != null);
|
||||
}
|
||||
public override bool RemoveWorksheet(uint worksheetPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
|
||||
// Extract Sheet by position.
|
||||
int sheetCount = 0;
|
||||
Sheet sheet = null;
|
||||
foreach (Sheet sheetCandidate in Sheets)
|
||||
{
|
||||
if (++sheetCount == worksheetPos)
|
||||
{
|
||||
sheet = sheetCandidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sheet != null)
|
||||
{
|
||||
// Extract the corresponding Worksheet Part.
|
||||
WorksheetPart worksheetPart = (WorksheetPart)(WorkbookPart.GetPartById(sheet.Id));
|
||||
// Check if the worksheet being removed is currently open.
|
||||
if (worksheet != null && sheet.Id == worksheet.Sheet.Id)
|
||||
CloseWorksheet();
|
||||
// Remove the sheet from the workbook.
|
||||
sheet.Remove();
|
||||
WorkbookPart.DeletePart(worksheetPart);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public override bool OpenWorksheet(uint worksheetPos)
|
||||
{
|
||||
String fn = GetType().Name + ".OpenWorksheet";
|
||||
ClearErrorState();
|
||||
CloseWorksheet();
|
||||
|
||||
// Extract Sheet by position.
|
||||
int sheetCount = 0;
|
||||
Sheet sheet = null;
|
||||
foreach (Sheet sheetCandidate in Sheets)
|
||||
{
|
||||
if (++sheetCount == worksheetPos)
|
||||
{
|
||||
sheet = sheetCandidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sheet != null)
|
||||
{
|
||||
WorksheetPart worksheetPart = (WorksheetPart)(WorkbookPart.GetPartById(sheet.Id));
|
||||
|
||||
if (worksheetPart != null && sheet != null)
|
||||
worksheet = new WorksheetData(worksheetPos, worksheetPart, sheet);
|
||||
}
|
||||
|
||||
if (worksheet != null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to open worksheet " + worksheetPos);
|
||||
SetErrorState("Failed to open worksheet " + worksheetPos);
|
||||
}
|
||||
|
||||
return (worksheet != null);
|
||||
}
|
||||
public override uint WorksheetPos { get { return activeWorksheetPos; } }
|
||||
public override String WorksheetName
|
||||
{
|
||||
get { return worksheet.Sheet.Name; }
|
||||
set { worksheet.Sheet.Name = StringUtil.Left(value, 31); }
|
||||
}
|
||||
public override bool SetWorksheetAttr(SaMsExcelItemAttr attr)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
// ToDo OpenXml SetWorksheetAttr
|
||||
}
|
||||
catch (Exception exc) { HandleException("SetWorksheetAttr", exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
public override bool CloseWorksheet()
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
if (worksheet != null)
|
||||
{
|
||||
// No worksheet components need to be disposed - they belong to the workbook.
|
||||
}
|
||||
worksheet = null;
|
||||
}
|
||||
catch (Exception exc) { HandleException("CloseWorksheet", exc); }
|
||||
worksheet = null;
|
||||
activeWorksheetPos = 0;
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Worksheet Page Setup.
|
||||
public override bool SetPageSetup(SaMsExcelPageSetup_Config pageSetupConfig)
|
||||
{
|
||||
//---------------------------------------------------------------
|
||||
// Page setup options:
|
||||
// ActiveSheet.PageSetup
|
||||
// .PrintTitleRows = "$4:$4"
|
||||
// .PrintTitleColumns = ""
|
||||
// .PrintArea = ""
|
||||
// .LeftHeader = ""
|
||||
// .CenterHeader = ""
|
||||
// .RightHeader = ""
|
||||
// .LeftFooter = ""
|
||||
// .CenterFooter = ""
|
||||
// .RightFooter = ""
|
||||
// .LeftMargin = Application.InchesToPoints(0.708661417322835)
|
||||
// .RightMargin = Application.InchesToPoints(0.708661417322835)
|
||||
// .TopMargin = Application.InchesToPoints(0.748031496062992)
|
||||
// .BottomMargin = Application.InchesToPoints(0.748031496062992)
|
||||
// .HeaderMargin = Application.InchesToPoints(0.31496062992126)
|
||||
// .FooterMargin = Application.InchesToPoints(0.31496062992126)
|
||||
// .PrintHeadings = False
|
||||
// .PrintGridlines = False
|
||||
// .PrintComments = xlPrintNoComments
|
||||
// .PrintQuality = 600
|
||||
// .CenterHorizontally = False
|
||||
// .CenterVertically = False
|
||||
// .Orientation = xlPortrait
|
||||
// .Draft = False
|
||||
// .PaperSize = xlPaperA4
|
||||
// .FirstPageNumber = xlAutomatic
|
||||
// .Order = xlDownThenOver
|
||||
// .BlackAndWhite = False
|
||||
// .Zoom = 100
|
||||
// .PrintErrors = xlPrintErrorsDisplayed
|
||||
// .OddAndEvenPagesHeaderFooter = False
|
||||
// .DifferentFirstPageHeaderFooter = False
|
||||
// .ScaleWithDocHeaderFooter = True
|
||||
// .AlignMarginsHeaderFooter = True
|
||||
// .EvenPage.LeftHeader.Text = ""
|
||||
// .EvenPage.CenterHeader.Text = ""
|
||||
// .EvenPage.RightHeader.Text = ""
|
||||
// .EvenPage.LeftFooter.Text = ""
|
||||
// .EvenPage.CenterFooter.Text = ""
|
||||
// .EvenPage.RightFooter.Text = ""
|
||||
// .FirstPage.LeftHeader.Text = ""
|
||||
// .FirstPage.CenterHeader.Text = ""
|
||||
// .FirstPage.RightHeader.Text = ""
|
||||
// .FirstPage.LeftFooter.Text = ""
|
||||
// .FirstPage.CenterFooter.Text = ""
|
||||
// .FirstPage.RightFooter.Text = ""
|
||||
//---------------------------------------------------------------
|
||||
// Negative values leave current value.
|
||||
ClearErrorState();
|
||||
if (worksheet == null) return false;
|
||||
try
|
||||
{
|
||||
// Page margins - must be before the Page Setup in the worksheet.
|
||||
PageMargins pageMargins = worksheet.WorksheetPart.Worksheet.GetFirstChild<PageMargins>();
|
||||
if (pageMargins == null)
|
||||
{
|
||||
pageMargins = new PageMargins();
|
||||
worksheet.WorksheetPart.Worksheet.AppendChild(pageMargins);
|
||||
}
|
||||
|
||||
// Page Setup.
|
||||
PageSetupProperties pageSetupProperties = worksheet.WorksheetPart.Worksheet.SheetProperties.PageSetupProperties;
|
||||
PageSetup pageSetup = worksheet.WorksheetPart.Worksheet.GetFirstChild<PageSetup>();
|
||||
if (pageSetup == null)
|
||||
{
|
||||
pageSetup = new PageSetup();
|
||||
worksheet.WorksheetPart.Worksheet.AppendChild(pageSetup);
|
||||
}
|
||||
|
||||
if (pageSetupConfig.Orientation == SaXlPageOrientation.xlLandscape)
|
||||
pageSetup.Orientation = OrientationValues.Landscape;
|
||||
else if (pageSetupConfig.Orientation == SaXlPageOrientation.xlPortrait)
|
||||
pageSetup.Orientation = OrientationValues.Portrait;
|
||||
// ToDo OpenXML Headers and footers.
|
||||
//pageSetup.LeftHeader = pageSetupConfig.HeaderLeft;
|
||||
//pageSetup.CenterHeader = pageSetupConfig.HeaderCenter;
|
||||
//pageSetup.RightHeader = pageSetupConfig.HeaderRight;
|
||||
//pageSetup.LeftFooter = pageSetupConfig.FooterLeft;
|
||||
//pageSetup.CenterFooter = pageSetupConfig.FooterCenter;
|
||||
//pageSetup.RightFooter = pageSetupConfig.FooterRight;
|
||||
// Margins.
|
||||
if (pageSetupConfig.MarginLeft > 0) pageMargins.Left = ToPoints(pageSetupConfig.MarginLeft, pageSetupConfig.Unit, false);
|
||||
if (pageSetupConfig.MarginRight > 0) pageMargins.Right = ToPoints(pageSetupConfig.MarginRight, pageSetupConfig.Unit, false);
|
||||
if (pageSetupConfig.MarginTop > 0) pageMargins.Top = ToPoints(pageSetupConfig.MarginTop, pageSetupConfig.Unit, true);
|
||||
if (pageSetupConfig.MarginBottom > 0) pageMargins.Bottom = ToPoints(pageSetupConfig.MarginBottom, pageSetupConfig.Unit, true);
|
||||
if (pageSetupConfig.MarginHeader > 0) pageMargins.Header = ToPoints(pageSetupConfig.MarginHeader, pageSetupConfig.Unit, true);
|
||||
if (pageSetupConfig.MarginFooter > 0) pageMargins.Footer = ToPoints(pageSetupConfig.MarginFooter, pageSetupConfig.Unit, true);
|
||||
/*
|
||||
* ToDo OpenXML PrintTitleRows/Columns
|
||||
// Print Title Rows.
|
||||
if (pageSetupConfig.PrintTitleRowFrom > 0 && pageSetupConfig.PrintTitleRowTo > 0)
|
||||
// Prefix with '$' to fix row value.(?)
|
||||
pageSetup.PrintTitleRows = "$" + GetRowSuffix((uint)pageSetupConfig.PrintTitleRowFrom) + ":$" + GetRowSuffix((uint)pageSetupConfig.PrintTitleRowTo);
|
||||
else if (pageSetupConfig.PrintTitleRowFrom == 0 && pageSetupConfig.PrintTitleRowTo == 0)
|
||||
pageSetup.PrintTitleRows = "";
|
||||
// Print Title Columns.
|
||||
if (pageSetupConfig.PrintTitleColFrom > 0 && pageSetupConfig.PrintTitleColTo > 0)
|
||||
pageSetup.PrintTitleColumns = "$" + GetColumnPrefix((uint)pageSetupConfig.PrintTitleColFrom) + ":$" + GetColumnPrefix((uint)pageSetupConfig.PrintTitleColTo);
|
||||
else if (pageSetupConfig.PrintTitleColFrom == 0 && pageSetupConfig.PrintTitleColTo == 0)
|
||||
pageSetup.PrintTitleColumns = "";
|
||||
*/
|
||||
/*
|
||||
// ToDo OpenXML Zoom and 'Fit to' options.
|
||||
if (pageSetupConfig.Zoom > 0)
|
||||
pageSetup.Zoom = pageSetupConfig.Zoom;
|
||||
else if (pageSetupConfig.FitToPagesTall > 0 || pageSetupConfig.FitToPagesWide > 0)
|
||||
{
|
||||
pageSetup.FitToPagesWide = Math.Min(0, pageSetupConfig.FitToPagesWide);
|
||||
pageSetup.FitToPagesTall = Math.Min(0, pageSetupConfig.FitToPagesTall);
|
||||
pageSetup.Zoom = 0;
|
||||
}
|
||||
*/
|
||||
}
|
||||
catch (Exception exc) { HandleException("SetPageSetup", exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
public override bool SetPageBreak(uint colPos, uint rowPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
if (worksheet == null) return false;
|
||||
try
|
||||
{
|
||||
/*
|
||||
* ToDo OpenXML Set page break
|
||||
String cellId = GetCellId(colPos, rowPos);
|
||||
Range range = worksheet.get_Range(cellId);
|
||||
worksheet.HPageBreaks.Add(range);
|
||||
worksheet.VPageBreaks.Add(range);
|
||||
*/
|
||||
}
|
||||
catch (Exception exc) { HandleException("SetPageSetup", exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public bool SelectRange()
|
||||
{
|
||||
// ToDo OpenXML Is SelectRange even relevant?
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// C o l u m n s
|
||||
//-------------------------------------------------------------------
|
||||
private Column GetColumnByPos (uint columnPos)
|
||||
{
|
||||
if (worksheet.ActiveColumnPos != columnPos)
|
||||
{
|
||||
// ToDo OpenXML GetColumnByPos.
|
||||
//Column column = worksheet.WorksheetPart.col
|
||||
}
|
||||
return worksheet.ActiveColumn;
|
||||
}
|
||||
public override uint GetActiveColPos()
|
||||
{
|
||||
if (worksheet == null) return 0;
|
||||
try
|
||||
{
|
||||
return worksheet.ActiveColumnPos;
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetActiveCol", exc); }
|
||||
return 0;
|
||||
}
|
||||
public override double GetColWidth(uint colPos, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
{
|
||||
double columnWidth = 0.0;
|
||||
try
|
||||
{
|
||||
// ToDo OpenXML GetColWidth.
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetColWidth", exc); }
|
||||
return columnWidth;
|
||||
}
|
||||
public override bool SetColWidth(uint colPos, double columnWidth, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
// ToDo OpenXML SetColWidth.
|
||||
}
|
||||
catch (Exception exc) { HandleException("SetColWidth", exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// R o w s
|
||||
//-------------------------------------------------------------------
|
||||
public override uint GetActiveRowPos()
|
||||
{
|
||||
try
|
||||
{
|
||||
// ToDo OpenXML GetActiveRowPos.
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetActiveRowPos", exc); }
|
||||
return 0;
|
||||
}
|
||||
public override List<DataValue> GetRowDataValues(uint rowPos, int maxColumns = 0)
|
||||
{
|
||||
List<DataValue> values = new List<DataValue>();
|
||||
return values;
|
||||
}
|
||||
public override double GetRowHeight(uint rowPos, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
{
|
||||
double rowHeight = 0.0;
|
||||
try
|
||||
{
|
||||
// ToDo OpenXML GetRowHeight.
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetRowHeight", exc); }
|
||||
return rowHeight;
|
||||
}
|
||||
public override bool SetRowHeight(uint rowPos, double rowHeight, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
// ToDo OpenXML SetRowHeight.
|
||||
}
|
||||
catch (Exception exc) { HandleException("SetRowHeight", exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// C e l l s
|
||||
//-------------------------------------------------------------------
|
||||
public override void SetActiveCell(uint colPos, uint rowPos)
|
||||
{
|
||||
// ToDo OpenXML SetActiveCell.
|
||||
}
|
||||
public override String GetCellFormula(uint colPos, uint rowPos)
|
||||
{
|
||||
// ToDo OpenXML GetCellFormula.
|
||||
return "";
|
||||
}
|
||||
public override DataValue GetCellDataValue(uint colPos, uint rowPos)
|
||||
{
|
||||
// ToDo OpenXML GetCellDataValue.
|
||||
return new DataValue();
|
||||
}
|
||||
public override bool SetCellFormula(uint colPos, uint rowPos, String value)
|
||||
{
|
||||
// ToDo OpenXML SetCellFormula.
|
||||
return true;
|
||||
}
|
||||
public override bool SetCellFormula(uint colPos, uint rowPos, String value, SaMsExcelItemAttr attr)
|
||||
{
|
||||
// ToDo OpenXML SetCellFormula.
|
||||
return true;
|
||||
}
|
||||
public override bool SetRowFormulas(uint colPosStart, uint rowPos, List<Object> values)
|
||||
{
|
||||
// ToDo OpenXML SetRowFormulas.
|
||||
return true;
|
||||
}
|
||||
public override bool SetRangeFormulas(SaMsExcelRange range, List<Object> values)
|
||||
{
|
||||
// ToDo OpenXML SetRangeFormulas.
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Cell attributes.
|
||||
public override bool SetRangeAttr(SaMsExcelRange range, SaMsExcelItemAttr attr)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
// ToDo OpenXML SetRangeAttr.
|
||||
}
|
||||
catch (Exception exc) { HandleException("SetRangeAttr", exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
private bool SetRangeAttr(Range oRange, SaMsExcelItemAttr attr)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
// ToDo OpenXML SetRangeAttr.
|
||||
}
|
||||
catch (Exception exc) { HandleException("SetRangeAttr", exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// I m a g e s
|
||||
//-------------------------------------------------------------------
|
||||
// Add image to sheet.
|
||||
public override bool InsertImage(SaMsExcelImage_Config imageConfig)
|
||||
{
|
||||
ClearErrorState();
|
||||
if (worksheet == null) return false;
|
||||
try
|
||||
{
|
||||
// ToDo OpenXML InsertImage.
|
||||
}
|
||||
catch (Exception exc) { HandleException("InsertImage", exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override bool FreezePanes(uint colPos, uint rowPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
// ToDo OpenXML FreezePanes.
|
||||
}
|
||||
catch (Exception exc) { HandleException("FreezePanes", exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override bool AutoFit(SaMsExcelRange range)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
// ToDo OpenXML AutoFit.
|
||||
}
|
||||
catch (Exception exc) { HandleException("AutoFit", exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override bool SelectRange(SaMsExcelRange range)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
// ToDo OpenXML SelectRange.
|
||||
}
|
||||
catch (Exception exc) { HandleException("SelectRange", exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,887 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Sarand.Net.Standard.Proc.Xml;
|
||||
using Sarand.Net.Standard.Proc.Zip;
|
||||
|
||||
namespace Sarand.Net.Standard.Proc.Excel
|
||||
{
|
||||
|
||||
//=======================================================================
|
||||
/// <summary>Excel spreadsheet read directly from xml data rather than via COM/Interop.</summary>
|
||||
public class SaMsSpreadsheet_POI : SaMsSpreadsheet
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
internal class Workbook
|
||||
{
|
||||
internal SaMsZipArchive WorkbookArchive { get; set; }
|
||||
internal SaMsXmlDocument WorkbookDoc { get; set; }
|
||||
internal SaMsXmlDocument SharedStringsDoc { get; set; }
|
||||
internal SaMsXmlDocument StylesDoc { get; set; }
|
||||
internal uint WorksheetCount { get; set; }
|
||||
internal uint ActiveSheetPos { get; set; }
|
||||
internal bool IsValid () { return (WorkbookDoc != null && WorkbookDoc.GetRootElement() != null); }
|
||||
}
|
||||
private Workbook workbook;
|
||||
private class Worksheet
|
||||
{
|
||||
internal uint WorksheetPos { get; set; }
|
||||
internal uint WorksheetId { get; set; }
|
||||
internal String WorksheetArchivePath { get; set; }
|
||||
internal String WorksheetName { get; set; }
|
||||
internal SaMsXmlDocument WorksheetDoc { get; set; }
|
||||
internal uint ActiveColPos { get; set; }
|
||||
internal uint ActiveRowPos { get; set; }
|
||||
internal class NodesData
|
||||
{
|
||||
internal SaMsXmlElement Cols { get; set; }
|
||||
internal SaMsXmlElement ActiveCol { get; set; }
|
||||
internal SaMsXmlElement Rows { get; set; }
|
||||
internal SaMsXmlElement ActiveRow { get; set; }
|
||||
}
|
||||
internal NodesData Nodes { get; } = new NodesData();
|
||||
bool IsValid () { return (WorksheetDoc != null && WorksheetDoc.GetRootElement() != null); }
|
||||
|
||||
}
|
||||
private Worksheet worksheet;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaMsSpreadsheet_POI () : base()
|
||||
{
|
||||
}
|
||||
protected override void Dispose (bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
CloseWorkbook();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// W o r k b o o k
|
||||
//-------------------------------------------------------------------
|
||||
public override bool IsWorkbookValid ()
|
||||
{
|
||||
return (workbook != null && workbook.IsValid());
|
||||
}
|
||||
public override bool CreateWorkbook ()
|
||||
{
|
||||
CloseWorkbook();
|
||||
ClearErrorState();
|
||||
|
||||
// Create new workbook.
|
||||
workbook = new Workbook();
|
||||
workbook.WorkbookArchive = new SaMsZipArchive();
|
||||
workbook.SharedStringsDoc = new SaMsXmlDocument();
|
||||
workbook.StylesDoc = new SaMsXmlDocument();
|
||||
|
||||
return SetErrorState("Creating workbook not supported");
|
||||
}
|
||||
public override bool OpenWorkbook (String filePath)
|
||||
{
|
||||
CloseWorkbook();
|
||||
ClearErrorState();
|
||||
if (!File.Exists(filePath))
|
||||
return SetErrorState("Workbook not found");
|
||||
List<String> validExtensions = new List<string>() { /*".xls",*/ ".xlsx", ".xlsb", ".zip" };
|
||||
String extension = Path.GetExtension(filePath);
|
||||
if (!validExtensions.ContainsCI(Path.GetExtension(filePath)))
|
||||
return SetErrorState("Invalid document type (expected xlsx/xlsb)");
|
||||
|
||||
try
|
||||
{
|
||||
// Open workbook document.
|
||||
workbook = new Workbook();
|
||||
workbook.WorkbookArchive = new SaMsZipArchive();
|
||||
if (workbook.WorkbookArchive.OpenArchive(filePath))
|
||||
{
|
||||
ExtractWorkbookElementsFromArchive();
|
||||
}
|
||||
else return SetErrorState("Failed to open document: " + workbook.WorkbookArchive.ErrorStateMessage);
|
||||
}
|
||||
catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
public bool OpenWorkbook (byte[] workbookData)
|
||||
{
|
||||
CloseWorkbook();
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
using (MemoryStream workbookStream = new MemoryStream(workbookData))
|
||||
{
|
||||
OpenWorkbook(workbookStream);
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
public bool OpenWorkbook (Stream workbookStream)
|
||||
{
|
||||
CloseWorkbook();
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
// From start of stream.
|
||||
workbookStream.Seek(0, SeekOrigin.Begin);
|
||||
// Open workbook document.
|
||||
workbook = new Workbook();
|
||||
workbook.WorkbookArchive = new SaMsZipArchive();
|
||||
if (workbook.WorkbookArchive.OpenArchive(workbookStream))
|
||||
{
|
||||
ExtractWorkbookElementsFromArchive();
|
||||
}
|
||||
else return SetErrorState("Failed to open document: " + workbook.WorkbookArchive.ErrorStateMessage);
|
||||
}
|
||||
catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
private bool ExtractWorkbookElementsFromArchive ()
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
// Extract the workbook data.
|
||||
using (MemoryStream workbookFile = workbook.WorkbookArchive.ExtractFileToStream("xl/workbook.xml"))
|
||||
{
|
||||
if (workbookFile == null) return SetErrorState("Failed to load workbook data");
|
||||
workbook.WorkbookDoc = new SaMsXmlDocument();
|
||||
if (workbook.WorkbookDoc.LoadXml(workbookFile))
|
||||
{
|
||||
// Workbook successfully opened.
|
||||
workbook.ActiveSheetPos = 1;
|
||||
// Shared strings:
|
||||
using (MemoryStream sharedStringsFile = workbook.WorkbookArchive.ExtractFileToStream("xl/sharedStrings.xml"))
|
||||
{
|
||||
if (sharedStringsFile != null)
|
||||
{
|
||||
workbook.SharedStringsDoc = new SaMsXmlDocument();
|
||||
workbook.SharedStringsDoc.LoadXml(sharedStringsFile);
|
||||
}
|
||||
}
|
||||
// Styles:
|
||||
using (MemoryStream stylesFile = workbook.WorkbookArchive.ExtractFileToStream("xl/styles.xml"))
|
||||
{
|
||||
if (stylesFile != null)
|
||||
{
|
||||
workbook.StylesDoc = new SaMsXmlDocument();
|
||||
workbook.StylesDoc.LoadXml(stylesFile);
|
||||
}
|
||||
}
|
||||
// Set worksheet count and open first worksheet.
|
||||
PopulateWorksheetCount();
|
||||
OpenWorksheet(1);
|
||||
}
|
||||
else return SetErrorState("Failed to read workbook data");
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
public override bool SaveDocument (String filePath, int fileFormat, bool bAutomaticallyOverwrite)
|
||||
{
|
||||
ClearErrorState();
|
||||
if (fileFormat == 0)
|
||||
fileFormat = (int)XlFileFormat.xlOpenXMLWorkbook;
|
||||
if (fileFormat != (int)XlFileFormat.xlOpenXMLWorkbook)
|
||||
SetErrorState("Unsupported file format: " + ((XlFileFormat)fileFormat).ToString());
|
||||
if (!HasErrorState() && !workbook.IsValid())
|
||||
SetErrorState("Workbook is not open");
|
||||
SetErrorState("Saving workbook not supported");
|
||||
return !HasErrorState();
|
||||
}
|
||||
public override bool CloseWorkbook ()
|
||||
{
|
||||
ClearErrorState();
|
||||
CloseWorksheet();
|
||||
|
||||
// Clear workbook.
|
||||
if (workbook != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (workbook.StylesDoc != null) workbook.StylesDoc.Dispose(); workbook.StylesDoc = null;
|
||||
if (workbook.SharedStringsDoc != null) workbook.SharedStringsDoc.Dispose(); workbook.SharedStringsDoc = null;
|
||||
if (workbook.WorkbookDoc != null) workbook.WorkbookDoc.Dispose(); workbook.WorkbookDoc = null;
|
||||
if (workbook.WorkbookArchive != null) workbook.WorkbookArchive.Dispose(); workbook.WorkbookArchive = null;
|
||||
}
|
||||
catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
workbook = null;
|
||||
}
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// W o r k s h e e t
|
||||
//-------------------------------------------------------------------
|
||||
public override bool IsWorksheetValid ()
|
||||
{
|
||||
return (worksheet != null && worksheet.WorksheetDoc != null);
|
||||
}
|
||||
public override uint WorksheetCount { get { return workbook.WorksheetCount; } }
|
||||
private void PopulateWorksheetCount ()
|
||||
{
|
||||
if (!IsWorkbookValid()) return;
|
||||
try
|
||||
{
|
||||
// Count worksheets in workbook.
|
||||
SaMsXmlElement nodeWorkbook = workbook.WorkbookDoc.GetRootElement();
|
||||
SaMsXmlElement nodeSheets = nodeWorkbook.GetFirstChildElement("sheets");
|
||||
workbook.WorksheetCount = (uint)nodeSheets.GetChildElements("sheet").Count;
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetWorksheetCount", exc); }
|
||||
}
|
||||
public override bool SetWorksheetCount (int worksheetCount)
|
||||
{
|
||||
ClearErrorState();
|
||||
return SetErrorState("Modifying workbook not supported");
|
||||
}
|
||||
public override bool AddWorksheet(String name)
|
||||
{
|
||||
return SetErrorState("Modifying workbook not supported");
|
||||
}
|
||||
public override bool RemoveWorksheet(uint worksheetPos)
|
||||
{
|
||||
return SetErrorState("Modifying workbook not supported");
|
||||
}
|
||||
public override bool OpenWorksheet (uint worksheetPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
if (!workbook.IsValid()) return SetErrorState("Workbook is not open");
|
||||
if (worksheetPos > WorksheetCount) return SetErrorState("Invalid sheet specified");
|
||||
if (worksheetPos <= 0) worksheetPos = Math.Max(1, workbook.ActiveSheetPos);
|
||||
CloseWorksheet();
|
||||
try
|
||||
{
|
||||
worksheet = new Worksheet();
|
||||
// Locate worksheet in workbook by 0-index.
|
||||
SaMsXmlElement workbookElement = workbook.WorkbookDoc.GetRootElement();
|
||||
SaMsXmlElement sheetsElement = workbookElement.GetFirstChildElement("sheets");
|
||||
long sheetCount = 0;
|
||||
foreach (SaMsXmlElement sheetElement in sheetsElement.GetChildElements("sheet"))
|
||||
{
|
||||
sheetCount++;
|
||||
if (sheetCount == worksheetPos)
|
||||
{
|
||||
// Extract the worksheet data.
|
||||
uint sheetId = (uint)StringUtil.ToInt(sheetElement.GetAttributeValue("sheetId"));
|
||||
String worksheetArchivePath = "xl/worksheets/sheet" + worksheetPos.ToString() + ".xml";
|
||||
using (MemoryStream worksheetFile = workbook.WorkbookArchive.ExtractFileToStream(worksheetArchivePath))
|
||||
{
|
||||
if (worksheetFile == null) return SetErrorState("Failed to load worksheet data");
|
||||
worksheet.WorksheetDoc = new SaMsXmlDocument();
|
||||
if (worksheet.WorksheetDoc.LoadXml(worksheetFile))
|
||||
{
|
||||
workbook.ActiveSheetPos = worksheetPos;
|
||||
worksheet.WorksheetPos = worksheetPos;
|
||||
worksheet.WorksheetId = sheetId;
|
||||
worksheet.WorksheetArchivePath = worksheetArchivePath;
|
||||
worksheet.WorksheetName = sheetElement.GetAttributeValue("name");
|
||||
worksheet.ActiveColPos = 1;
|
||||
worksheet.ActiveRowPos = 1;
|
||||
SaMsXmlElement nodeWorksheet = worksheet.WorksheetDoc.GetRootElement();
|
||||
worksheet.Nodes.Cols = nodeWorksheet.GetFirstChildElement("cols");
|
||||
worksheet.Nodes.ActiveCol = worksheet.Nodes.Cols.GetFirstChildElement("col");
|
||||
worksheet.Nodes.Rows = nodeWorksheet.GetFirstChildElement("sheetData");
|
||||
worksheet.Nodes.ActiveRow = worksheet.Nodes.Rows.GetFirstChildElement("row");
|
||||
workbook.ActiveSheetPos = worksheetPos;
|
||||
}
|
||||
else return SetErrorState("Failed to read data for worksheet " + worksheetPos.ToString());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (worksheet.WorksheetDoc == null) return SetErrorState("Unable to load worksheet " + worksheetPos.ToString());
|
||||
}
|
||||
catch (Exception exc) { HandleException("OpenWorksheet", exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
public override uint WorksheetPos { get { return workbook.ActiveSheetPos; } }
|
||||
public override String WorksheetName
|
||||
{
|
||||
get { return ""; }
|
||||
set { }
|
||||
}
|
||||
public override bool SetWorksheetAttr (SaMsExcelItemAttr attr)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
public override bool CloseWorksheet ()
|
||||
{
|
||||
ClearErrorState();
|
||||
|
||||
if (worksheet != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (worksheet.WorksheetDoc != null) worksheet.WorksheetDoc.Dispose(); worksheet.WorksheetDoc = null;
|
||||
if (worksheet.Nodes.Cols != null) worksheet.Nodes.Cols.Dispose(); worksheet.Nodes.Cols = null;
|
||||
if (worksheet.Nodes.ActiveCol != null) worksheet.Nodes.ActiveCol.Dispose(); worksheet.Nodes.ActiveCol = null;
|
||||
if (worksheet.Nodes.Rows != null) worksheet.Nodes.Rows.Dispose(); worksheet.Nodes.Rows = null;
|
||||
if (worksheet.Nodes.ActiveRow != null) worksheet.Nodes.ActiveRow.Dispose(); worksheet.Nodes.ActiveRow = null;
|
||||
}
|
||||
catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
worksheet = null;
|
||||
}
|
||||
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Worksheet Page Setup.
|
||||
public override bool SetPageSetup (SaMsExcelPageSetup_Config pageSetupConfig)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
public override bool SetPageBreak (uint col, uint row)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// C o l u m n s
|
||||
//-------------------------------------------------------------------
|
||||
public override uint GetActiveColPos ()
|
||||
{
|
||||
return worksheet.ActiveColPos;
|
||||
}
|
||||
private SaMsXmlElement GetColElement (uint colPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
if (worksheet.ActiveColPos == colPos) return worksheet.Nodes.ActiveCol;
|
||||
int colCount = 0;
|
||||
foreach (SaMsXmlElement colElement in worksheet.Nodes.Cols.GetChildElements("Col"))
|
||||
{
|
||||
if (++colCount == colPos)
|
||||
{
|
||||
if (worksheet.Nodes.ActiveCol != null) worksheet.Nodes.ActiveCol.Dispose();
|
||||
worksheet.ActiveColPos = colPos;
|
||||
worksheet.Nodes.ActiveCol = colElement;
|
||||
return colElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetColElement", exc); }
|
||||
return new SaMsXmlElement(null);
|
||||
}
|
||||
public override double GetColWidth (uint colPos, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
// Retrieve width (in points) from column.
|
||||
SaMsXmlNode nodeCol = GetColElement(colPos);
|
||||
double width = nodeCol.GetAttributeValue("width").ToDouble();
|
||||
// Adjust for units.
|
||||
if (unit == SaExcelLogicalUnit.Pixel) return PointsToPixels(width, false);
|
||||
if (unit == SaExcelLogicalUnit.Cm) return PointsToCms(width);
|
||||
if (unit == SaExcelLogicalUnit.Inch) return PointsToInches(width);
|
||||
return width;
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetColWidth", exc); }
|
||||
return 0.0;
|
||||
}
|
||||
public override bool SetColWidth (uint colPos, double fWidth, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// R o w s
|
||||
//-------------------------------------------------------------------
|
||||
public override uint GetActiveRowPos ()
|
||||
{
|
||||
return worksheet.ActiveRowPos;
|
||||
}
|
||||
SaMsXmlElement GetRowElement (uint rowPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
if (worksheet.ActiveRowPos == rowPos) return worksheet.Nodes.ActiveRow;
|
||||
foreach (SaMsXmlElement rowElement in worksheet.Nodes.Rows.GetChildElements("row"))
|
||||
{
|
||||
if (rowElement.GetAttributeValue("r").ToLong() == rowPos)
|
||||
{
|
||||
if (worksheet.Nodes.ActiveRow != null) worksheet.Nodes.ActiveRow.Dispose();
|
||||
worksheet.ActiveRowPos = rowPos;
|
||||
worksheet.Nodes.ActiveRow = rowElement;
|
||||
return rowElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetRowElement", exc); }
|
||||
return new SaMsXmlElement(null);
|
||||
}
|
||||
public override double GetRowHeight (uint rowPos, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
// Retrieve height (in points) from row.
|
||||
SaMsXmlElement rowElement = GetRowElement(rowPos);
|
||||
double height = rowElement.GetAttributeValue("ht").ToDouble();
|
||||
// Adjust for units.
|
||||
if (unit == SaExcelLogicalUnit.Pixel) return PointsToPixels(height, true);
|
||||
if (unit == SaExcelLogicalUnit.Cm) return PointsToCms(height);
|
||||
if (unit == SaExcelLogicalUnit.Inch) return PointsToInches(height);
|
||||
return height;
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetRowHeight", exc); }
|
||||
return 0.0;
|
||||
}
|
||||
public override bool SetRowHeight (uint rowPos, double fHeight, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// R o w s
|
||||
//-------------------------------------------------------------------
|
||||
public override List<DataValue> GetRowDataValues (uint rowPos, int maxColumns = 0)
|
||||
{
|
||||
ClearErrorState();
|
||||
List<DataValue> values = new List<DataValue>();
|
||||
try
|
||||
{
|
||||
SaMsXmlElement rowElement = GetRowElement(rowPos);
|
||||
foreach (SaMsXmlElement cellElement in rowElement.GetChildElements("c"))
|
||||
{
|
||||
// CellId may be needed in case cells are skipped in the data.
|
||||
// Doesn't appear to be the case, even when previous cell is merged with next.
|
||||
String cellId = cellElement.GetAttributeValue("r");
|
||||
values.Add(GetCellDataValue(cellElement));
|
||||
if (maxColumns > 0 && values.Count >= maxColumns) break;
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetRowDataValues", exc); }
|
||||
return values;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// C e l l s
|
||||
//-------------------------------------------------------------------
|
||||
SaMsXmlElement GetCellElement (uint colPos, uint rowPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
String cellId = GetCellId(colPos,rowPos);
|
||||
try
|
||||
{
|
||||
SaMsXmlElement rowElement = GetRowElement(rowPos);
|
||||
foreach (SaMsXmlElement cellElement in rowElement.GetChildElements("c"))
|
||||
{
|
||||
if (cellElement.GetAttributeValue("r").EqualsCI(cellId))
|
||||
return cellElement;
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetCellElement", exc); }
|
||||
return new SaMsXmlElement(null);
|
||||
}
|
||||
public override void SetActiveCell (uint colPos, uint rowPos)
|
||||
{
|
||||
// ToDo SetActiveCell.
|
||||
SetErrorState("Not supported");
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
private bool IsCellFormula (uint colPos, uint rowPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
bool bIsFormula = false;
|
||||
try
|
||||
{
|
||||
SaMsXmlElement cellElement = GetCellElement(colPos,rowPos);
|
||||
bIsFormula = !cellElement.GetAttributeValue("f").IsEmpty();
|
||||
}
|
||||
catch (Exception exc) { HandleException("IsCellFormula", exc); }
|
||||
return bIsFormula;
|
||||
}
|
||||
private bool IsCellNumeric (uint colPos, uint rowPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
SaMsXmlElement cellElement = GetCellElement(colPos,rowPos);
|
||||
SaMsExcelStyle cellStyle = GetCellStyle(cellElement);
|
||||
return IsCellNumeric(cellElement, cellStyle);
|
||||
}
|
||||
catch (Exception exc) { HandleException("IsCellNumeric", exc); }
|
||||
return false;
|
||||
}
|
||||
private bool IsCellNumeric (SaMsXmlElement cellElement)
|
||||
{
|
||||
ClearErrorState();
|
||||
SaMsExcelStyle cellStyle = GetCellStyle(cellElement);
|
||||
return IsCellNumeric(cellElement, cellStyle);
|
||||
}
|
||||
private bool IsCellNumeric (SaMsXmlElement cellElement, SaMsExcelStyle cellStyle)
|
||||
{
|
||||
ClearErrorState();
|
||||
return (cellElement.GetAttributeValue("t").IsEmpty() && !IsDateTimeStyle(cellStyle.NumFmtCode));
|
||||
}
|
||||
private bool IsCellDate (uint colPos, uint rowPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
bool bIsDate = false;
|
||||
try
|
||||
{
|
||||
SaMsXmlElement cellElement = GetCellElement(colPos,rowPos);
|
||||
SaMsExcelStyle cellStyle = GetCellStyle(cellElement);
|
||||
return IsCellDate(cellElement, cellStyle);
|
||||
}
|
||||
catch (Exception exc) { HandleException("IsCellDate", exc); }
|
||||
return bIsDate;
|
||||
}
|
||||
private bool IsCellDate (SaMsXmlElement cellElement)
|
||||
{
|
||||
return IsCellDate(cellElement, GetCellStyle(cellElement));
|
||||
}
|
||||
private bool IsCellDate (SaMsXmlElement cellElement, SaMsExcelStyle cellStyle)
|
||||
{
|
||||
ClearErrorState();
|
||||
return IsDateTimeStyle(cellStyle.NumFmtCode);
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
public override String GetCellFormula (uint colPos, uint rowPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
SaMsXmlElement cellElement = GetCellElement(colPos,rowPos);
|
||||
String formula = cellElement.GetAttributeValue("f");
|
||||
if (formula.IsEmpty())
|
||||
formula = GetCellText(cellElement, true);
|
||||
return formula;
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetCellFormula", exc); }
|
||||
return "";
|
||||
}
|
||||
private String GetCellText (SaMsXmlElement cellElement, bool trimValue = true)
|
||||
{
|
||||
ClearErrorState();
|
||||
String value = "";
|
||||
try
|
||||
{
|
||||
if (cellElement.GetAttributeValue("t").EqualsCI("s"))
|
||||
value = GetSharedString(cellElement);
|
||||
else
|
||||
value = cellElement.GetChildText("v");
|
||||
if (trimValue) value.TrimAll();
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetCellText", exc); }
|
||||
return value;
|
||||
}
|
||||
public override DataValue GetCellDataValue (uint colPos, uint rowPos)
|
||||
{
|
||||
return GetCellDataValue(GetCellElement(colPos, rowPos), false);
|
||||
}
|
||||
private DataValue GetCellDataValue (SaMsXmlElement cellElement, bool trimTextValue = true)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
SaMsExcelStyle cellStyle = GetCellStyle(cellElement);
|
||||
if (cellElement.GetAttributeValue("t").EqualsCI("s"))
|
||||
{
|
||||
String value = GetSharedString(cellElement);
|
||||
if (trimTextValue) value = value.TrimAll();
|
||||
return new DataValue(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
String value = cellElement.GetChildText("v");
|
||||
if (IsDateTimeStyle(cellStyle.NumFmtCode))
|
||||
return new DataValue(DateTime.FromOADate(value.ToDouble()));
|
||||
if (IsCellNumeric(cellElement, cellStyle))
|
||||
{
|
||||
if (value.IsNumeric())
|
||||
return new DataValue(value.ToLong());
|
||||
if (value.IsDecimal())
|
||||
{
|
||||
#if DEBUG
|
||||
//if (StringUtil.ToInt(value) > 600) Debugger.Break();
|
||||
#endif
|
||||
return new DataValue(value.ToDecimal());
|
||||
}
|
||||
}
|
||||
if (trimTextValue) value = value.TrimAll();
|
||||
return new DataValue(value);
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetCellDataValue", exc); }
|
||||
return new DataValue();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
// Shared string for cell.
|
||||
private String GetSharedString (SaMsXmlElement nodeElement)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
SaMsXmlElement sharedStringElement = GetSharedStringElement(nodeElement);
|
||||
return sharedStringElement.GetChildText("t");
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetSharedString", exc); }
|
||||
return "";
|
||||
}
|
||||
private SaMsXmlElement GetSharedStringElement (SaMsXmlElement cellElement)
|
||||
{
|
||||
ClearErrorState();
|
||||
if (workbook.SharedStringsDoc == null || cellElement == null || !cellElement.Valid) return null;
|
||||
if (!cellElement.GetAttributeValue("t").EqualsCI("s") || !cellElement.GetChildText("v").IsNumeric()) return null;
|
||||
// Shared strings are indexed from 0.
|
||||
long sharedStringIdx = -1;
|
||||
try
|
||||
{
|
||||
long iIdx = cellElement.GetChildText("v").ToLong();
|
||||
SaMsXmlElement sstElement = workbook.SharedStringsDoc.GetRootElement();
|
||||
foreach (SaMsXmlElement siElement in sstElement.GetChildElements("si"))
|
||||
{
|
||||
if (++sharedStringIdx == iIdx)
|
||||
return siElement;
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetSharedStringNode", exc); }
|
||||
return new SaMsXmlElement(null);
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
public override bool SetCellFormula (uint colPos, uint rowPos, String value)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
public override bool SetCellFormula (uint colPos, uint rowPos, String value, SaMsExcelItemAttr attr)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
public override bool SetRowFormulas (uint colPosStart, uint rowPos, List<Object> values)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
public override bool SetRangeFormulas (SaMsExcelRange range, List<Object> values)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// C e l l S t y l e
|
||||
//-------------------------------------------------------------------
|
||||
private String GetBuiltInStyleFormat (int numFmtId)
|
||||
{
|
||||
// Ref. http://stackoverflow.com/questions/4730152/what-indicates-an-office-open-xml-cell-contains-a-date-time-value
|
||||
switch (numFmtId)
|
||||
{
|
||||
//
|
||||
case 0: return "General";
|
||||
case 1: return "0";
|
||||
case 2: return "0.00";
|
||||
case 3: return "#,##0";
|
||||
case 4: return "#,##0.00";
|
||||
//
|
||||
case 9: return "0%";
|
||||
case 10: return "0.00%";
|
||||
case 11: return "0.00E+00";
|
||||
case 12: return "# ?/?";
|
||||
case 13: return "# ??/??";
|
||||
case 14: return "mm-dd-yy";
|
||||
case 15: return "d-mmm-yy";
|
||||
case 16: return "d-mmm";
|
||||
case 17: return "mmm-yy";
|
||||
case 18: return "h:mm AM/PM";
|
||||
case 19: return "h:mm:ss AM/PM";
|
||||
case 20: return "h:mm";
|
||||
case 21: return "h:mm:ss";
|
||||
case 22: return "m/d/yy h:mm";
|
||||
//
|
||||
case 37: return "#,##0 ;(#,##0)";
|
||||
case 38: return "#,##0 ;[Red](#,##0)";
|
||||
case 39: return "#,##0.00;(#,##0.00)";
|
||||
case 40: return "#,##0.00;[Red](#,##0.00)";
|
||||
//
|
||||
case 44: return "_(\"$\"* #,##0.00_);_(\"$\"* \\(#,##0.00\\);_(\"$\"* \"-\"??_);_(@_)";
|
||||
case 45: return "mm:ss";
|
||||
case 46: return "[h]:mm:ss";
|
||||
case 47: return "mmss.0";
|
||||
case 48: return "##0.0E+0";
|
||||
case 49: return "@";
|
||||
//
|
||||
case 27: return "[$-404]e/m/d";
|
||||
case 30: return "m/d/yy";
|
||||
case 36: return "[$-404]e/m/d";
|
||||
case 50: return "[$-404]e/m/d";
|
||||
case 57: return "[$-404]e/m/d";
|
||||
//
|
||||
case 59: return "t0";
|
||||
case 60: return "t0.00";
|
||||
case 61: return "t#,##0";
|
||||
case 62: return "t#,##0.00";
|
||||
case 67: return "t0%";
|
||||
case 68: return "t0.00%";
|
||||
case 69: return "t# ?/?";
|
||||
case 70: return "t# ??/??";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
private SaMsExcelStyle GetCellStyle (SaMsXmlElement cellElement)
|
||||
{
|
||||
ClearErrorState();
|
||||
SaMsExcelStyle style = new SaMsExcelStyle();
|
||||
if (workbook.SharedStringsDoc == null || cellElement == null || !cellElement.Valid || !cellElement.GetAttributeValue("s").IsNumeric()) return style;
|
||||
// Styles are indexed from 0.
|
||||
long styleIdx = -1;
|
||||
try
|
||||
{
|
||||
long cellStyleIdx = cellElement.GetAttributeValue("s").ToLong();
|
||||
SaMsXmlElement styleSheetElement = workbook.SharedStringsDoc.GetRootElement();
|
||||
SaMsXmlElement cellXfsElement = styleSheetElement.GetFirstChildElement("cellXfs");
|
||||
foreach (SaMsXmlElement xfElement in styleSheetElement.GetChildElements("xf"))
|
||||
{
|
||||
if (++styleIdx == cellStyleIdx)
|
||||
{
|
||||
// Construct style.
|
||||
style.NumFmtId = (int)xfElement.GetAttributeValue("numFmtId").ToLong();
|
||||
style.FontId = (int)xfElement.GetAttributeValue("fontId").ToLong();
|
||||
style.FillId = (int)xfElement.GetAttributeValue("fillId").ToLong();
|
||||
style.BorderId = (int)xfElement.GetAttributeValue("borderId").ToLong();
|
||||
style.XfId = (int)xfElement.GetAttributeValue("xfId").ToLong();
|
||||
style.QuotePrefix = xfElement.GetAttributeValue("quotePrefix").ToBool();
|
||||
style.PivotButton = xfElement.GetAttributeValue("pivotButton").ToBool();
|
||||
style.ApplyNumberFormat = xfElement.GetAttributeValue("applyNumberFormat").ToBool();
|
||||
style.ApplyFont = xfElement.GetAttributeValue("applyFont").ToBool();
|
||||
style.ApplyFill = xfElement.GetAttributeValue("applyFill").ToBool();
|
||||
style.ApplyBorder = xfElement.GetAttributeValue("applyBorder").ToBool();
|
||||
style.ApplyAlignment = xfElement.GetAttributeValue("applyAlignment").ToBool();
|
||||
style.ApplyProtection = xfElement.GetAttributeValue("applyProtection").ToBool();
|
||||
// Alignment.
|
||||
SaMsXmlNode nodeAlignment = xfElement.GetFirstChildElement("alignment");
|
||||
String sAlignHorizontal = nodeAlignment.GetAttributeValue("horizontal");
|
||||
if (sAlignHorizontal.EqualsCI("center")) style.AlignHorizontal = XlHAlign.xlHAlignCenter;
|
||||
else if (sAlignHorizontal.EqualsCI("centerContinuous")) style.AlignHorizontal = XlHAlign.xlHAlignCenterAcrossSelection;
|
||||
else if (sAlignHorizontal.EqualsCI("distributed")) style.AlignHorizontal = XlHAlign.xlHAlignDistributed;
|
||||
else if (sAlignHorizontal.EqualsCI("fill")) style.AlignHorizontal = XlHAlign.xlHAlignFill;
|
||||
else if (sAlignHorizontal.EqualsCI("justify")) style.AlignHorizontal = XlHAlign.xlHAlignJustify;
|
||||
else if (sAlignHorizontal.EqualsCI("left")) style.AlignHorizontal = XlHAlign.xlHAlignLeft;
|
||||
else if (sAlignHorizontal.EqualsCI("right")) style.AlignHorizontal = XlHAlign.xlHAlignRight;
|
||||
String sAlignVertical = nodeAlignment.GetAttributeValue("vertical");
|
||||
if (sAlignVertical.EqualsCI("center")) style.AlignVertical = XlVAlign.xlVAlignCenter;
|
||||
else if (sAlignVertical.EqualsCI("top")) style.AlignVertical = XlVAlign.xlVAlignTop;
|
||||
else if (sAlignVertical.EqualsCI("bottom")) style.AlignVertical = XlVAlign.xlVAlignBottom;
|
||||
else if (sAlignVertical.EqualsCI("distributed")) style.AlignVertical = XlVAlign.xlVAlignDistributed;
|
||||
else if (sAlignVertical.EqualsCI("justify")) style.AlignVertical = XlVAlign.xlVAlignJustify;
|
||||
// Number format.
|
||||
if (style.ApplyNumberFormat)
|
||||
{
|
||||
if (style.NumFmtId >= 164)
|
||||
{
|
||||
SaMsXmlElement numFmtsElement = styleSheetElement.GetFirstChildElement("NumFmts");
|
||||
foreach (SaMsXmlElement numFmtElement in numFmtsElement.GetChildElements("numFmt"))
|
||||
{
|
||||
if (numFmtElement.GetAttributeValue("numFmtId").ToLong() == style.NumFmtId)
|
||||
{
|
||||
style.NumFmtCode = numFmtElement.GetAttributeValue("formatCode");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else style.NumFmtCode = GetBuiltInStyleFormat(style.NumFmtId);
|
||||
}
|
||||
// Font.
|
||||
if (style.ApplyFont)
|
||||
{
|
||||
}
|
||||
// Fill.
|
||||
if (style.ApplyFill)
|
||||
{
|
||||
}
|
||||
// Borders.
|
||||
if (style.ApplyBorder)
|
||||
{
|
||||
}
|
||||
// Alignment.
|
||||
if (style.ApplyAlignment)
|
||||
{
|
||||
}
|
||||
// Protection.
|
||||
if (style.ApplyProtection)
|
||||
{
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetStyleNode", exc); }
|
||||
return style;
|
||||
}
|
||||
private bool IsDateStyle (String numFormat)
|
||||
{
|
||||
// Ref. http://stackoverflow.com/questions/19034805/how-to-distinguish-inline-numbers-from-ole-automation-date-numbers-in-openxml-sp/19582685#19582685
|
||||
if (IsTimeStyle(numFormat)) return false;
|
||||
if (numFormat.Contains("d")) return true;
|
||||
if (numFormat.Contains("m")) return true;
|
||||
if (numFormat.Contains("y")) return true;
|
||||
return false;
|
||||
}
|
||||
private bool IsTimeStyle (String numFormat)
|
||||
{
|
||||
if (numFormat.Contains("h")) return true;
|
||||
if (numFormat.Contains(":mm")) return true;
|
||||
if (numFormat.Contains("mm:")) return true;
|
||||
if (numFormat.Contains(":ss")) return true;
|
||||
return false;
|
||||
}
|
||||
private bool IsDateTimeStyle (String numFormat)
|
||||
{
|
||||
return (IsDateStyle(numFormat) || IsTimeStyle(numFormat));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Cell attributes.
|
||||
public override bool SetRangeAttr (SaMsExcelRange range, SaMsExcelItemAttr attr)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Add image to sheet.
|
||||
public override bool InsertImage (SaMsExcelImage_Config imageConfig)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override bool FreezePanes (uint colPos, uint rowPos)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override bool AutoFit (SaMsExcelRange range)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override bool SelectRange (SaMsExcelRange range)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using Sarand.Net.Standard.Base.Procs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Sarand.Net.Standard.Proc.Procs
|
||||
{
|
||||
//=======================================================================
|
||||
public abstract class SaProcess : SaProcess_Base
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Definitions.
|
||||
public new class Config : SaProcess_Base.Config
|
||||
{
|
||||
protected Config() : base()
|
||||
{ }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private Config config;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
protected SaProcess(Config config) :
|
||||
base(config)
|
||||
{
|
||||
this.config = config;
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Utilities.
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Run asynchronous.
|
||||
//-------------------------------------------------------------------
|
||||
public bool RunAsync()
|
||||
{
|
||||
// Run on separate thread.
|
||||
Thread thread = new Thread(new ThreadStart(RunOnThread));
|
||||
thread.IsBackground = true;
|
||||
thread.Start();
|
||||
return true;
|
||||
}
|
||||
private void RunOnThread()
|
||||
{
|
||||
RunProcess();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
|
||||
namespace Sarand.Net.Standard.Proc.Xml
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaMsXmlDocument : SaErrorStateItem
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private XmlDocument document = new XmlDocument();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaMsXmlDocument ()
|
||||
{
|
||||
}
|
||||
protected override void Dispose (bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
document = null;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
public bool Valid { get { return (document != null); } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// O p e n
|
||||
//-------------------------------------------------------------------
|
||||
public bool CreateNew (String rootElementName = "")
|
||||
{
|
||||
ClearErrorState();
|
||||
document = new XmlDocument();
|
||||
if (!StringUtil.IsEmpty(rootElementName))
|
||||
document.AppendElement(rootElementName);
|
||||
return !HasErrorState();
|
||||
}
|
||||
public bool LoadXml (String xml)
|
||||
{
|
||||
ClearErrorState();
|
||||
document = new XmlDocument();
|
||||
try
|
||||
{
|
||||
document.LoadXml(xml);
|
||||
}
|
||||
catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
public bool LoadXml (Stream xml)
|
||||
{
|
||||
ClearErrorState();
|
||||
document = new XmlDocument();
|
||||
try
|
||||
{
|
||||
xml.Seek(0, SeekOrigin.Begin);
|
||||
document.Load(xml);
|
||||
}
|
||||
catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// C o n v e r s i o n
|
||||
//-------------------------------------------------------------------
|
||||
public static Encoding DefaultEncoding { get; } = Encoding.UTF8;
|
||||
public String GetXml (Encoding encoding = null)
|
||||
{
|
||||
return document.GetXml(encoding != null ? encoding : DefaultEncoding);
|
||||
}
|
||||
public String FormatXml (Encoding encoding = null)
|
||||
{
|
||||
return document.FormatXml(encoding != null ? encoding : DefaultEncoding);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// E l e m e n t s
|
||||
//-------------------------------------------------------------------
|
||||
public SaMsXmlElement GetRootElement ()
|
||||
{
|
||||
if (document != null) return new SaMsXmlElement(document.DocumentElement);
|
||||
return null;
|
||||
}
|
||||
public SaMsXmlElement SetRootElement (String name)
|
||||
{
|
||||
// Clear existing root element.
|
||||
if (document.DocumentElement != null)
|
||||
document.DocumentElement.ParentNode.RemoveAll();
|
||||
// Add the new root element.
|
||||
return new SaMsXmlElement(document.AppendElement(name));
|
||||
}
|
||||
public SaMsXmlElement SetRootElement (SaXmlNamespace xmlNamespace, String name)
|
||||
{
|
||||
// Clear existing root element.
|
||||
if (document.DocumentElement != null)
|
||||
document.DocumentElement.ParentNode.RemoveAll();
|
||||
// Add the new root element.
|
||||
return new SaMsXmlElement(document.AppendElement(xmlNamespace, name));
|
||||
}
|
||||
public SaMsXmlElement SetRootElement (SaMsXmlElement rootNode)
|
||||
{
|
||||
// Clear existing root element.
|
||||
if (document.DocumentElement != null)
|
||||
document.DocumentElement.ParentNode.RemoveAll();
|
||||
// Import the node into the document before appending.
|
||||
XmlNode importNode = document.ImportNode(rootNode.Element, true);
|
||||
document.AppendChild(importNode);
|
||||
return rootNode;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
|
||||
namespace Sarand.Net.Standard.Proc.Xml
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaMsXmlElement : SaMsXmlNode
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
internal SaMsXmlElement (XmlElement element) :
|
||||
base(element)
|
||||
{
|
||||
}
|
||||
protected override void Dispose (bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
internal XmlElement Element { get { return (node as XmlElement); } }
|
||||
public override bool Valid { get { return (Element != null); } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// A t t r i b u t e s
|
||||
//-------------------------------------------------------------------
|
||||
public Dictionary<String, String> GetAttributes ()
|
||||
{
|
||||
Dictionary<String, String> attributes = new Dictionary<string, string>();
|
||||
foreach (XmlAttribute attribute in Element.Attributes)
|
||||
attributes[attribute.Name] = attribute.Value;
|
||||
return attributes;
|
||||
}
|
||||
public bool HasAttribute (String name, bool caseInsensitive = false)
|
||||
{
|
||||
foreach (XmlAttribute attribute in Element.Attributes)
|
||||
{
|
||||
if ((!caseInsensitive && attribute.Name.Equals(name)) || (caseInsensitive && attribute.Name.EqualsCI(name)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public String GetAttribute (String name, bool caseInsensitive = false)
|
||||
{
|
||||
foreach (XmlAttribute attribute in Element.Attributes)
|
||||
{
|
||||
if ((!caseInsensitive && attribute.Name.Equals(name)) || (caseInsensitive && attribute.Name.EqualsCI(name)))
|
||||
return attribute.Value;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
public void SetAttribute (String name, String value)
|
||||
{
|
||||
Element.SetAttribute(name, value);
|
||||
}
|
||||
public bool RemoveAttribute (String name, bool caseInsensitive = false)
|
||||
{
|
||||
if (!HasAttribute(name, caseInsensitive)) return false;
|
||||
for (int attributeIdx =0; attributeIdx < Element.Attributes.Count; attributeIdx++)
|
||||
{
|
||||
XmlAttribute attribute = Element.Attributes[attributeIdx];
|
||||
if ((!caseInsensitive && attribute.Name.Equals(name)) || (caseInsensitive && attribute.Name.EqualsCI(name)))
|
||||
{
|
||||
Element.Attributes.RemoveAt(attributeIdx);
|
||||
attributeIdx--;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// C h i l d E l e m e n t s
|
||||
//-------------------------------------------------------------------
|
||||
public List<SaMsXmlElement> GetChildElements (String name = "")
|
||||
{
|
||||
List<SaMsXmlElement> childElements = new List<SaMsXmlElement>();
|
||||
XmlElement element = Element;
|
||||
if (element == null) return childElements;
|
||||
foreach (XmlNode childNode in element.ChildNodes)
|
||||
{
|
||||
if (StringUtil.IsEmpty(name) || childNode.Name.EqualsCI(name))
|
||||
childElements.Add(new SaMsXmlElement(childNode as XmlElement));
|
||||
}
|
||||
return childElements;
|
||||
}
|
||||
public bool HasChildElement (String name)
|
||||
{
|
||||
XmlElement element = Element;
|
||||
if (element == null) return false;
|
||||
foreach (XmlNode childNode in element.ChildNodes)
|
||||
{
|
||||
if (childNode.NodeType == XmlNodeType.Element && StringUtil.IsEmpty(name) || childNode.Name.EqualsCI(name))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public SaMsXmlElement GetFirstChildElement (String name = "")
|
||||
{
|
||||
XmlElement element = Element;
|
||||
if (element == null) return null;
|
||||
foreach (XmlNode childNode in element.ChildNodes)
|
||||
{
|
||||
if (childNode.NodeType == XmlNodeType.Element && StringUtil.IsEmpty(name) || childNode.Name.EqualsCI(name))
|
||||
return new SaMsXmlElement(childNode as XmlElement);
|
||||
}
|
||||
return new SaMsXmlElement(null);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// A p p e n d E l e m e n t s
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Append element to node by name.</summary>
|
||||
public SaMsXmlElement AppendElement (String name, String text = "")
|
||||
{
|
||||
XmlDocument doc = Element.OwnerDocument;
|
||||
XmlElement child = (XmlElement)Element.AppendChild(doc.CreateElement(name));
|
||||
if (!StringUtil.IsEmpty(text))
|
||||
child.AppendChild(doc.CreateTextNode(text));
|
||||
return new SaMsXmlElement(child);
|
||||
}
|
||||
public SaMsXmlElement AppendElement (SaXmlNamespace xmlNamespace, String name, String text = "")
|
||||
{
|
||||
XmlDocument doc = Element.OwnerDocument;
|
||||
XmlElement child = (XmlElement)Element.AppendChild(doc.CreateElement(xmlNamespace.Prefix, name, xmlNamespace.Uri));
|
||||
if (!StringUtil.IsEmpty(text))
|
||||
child.AppendChild(doc.CreateTextNode(text));
|
||||
return new SaMsXmlElement(child);
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Append element to node by name if value supplied.</summary>
|
||||
public SaMsXmlElement AppendNonBlankElement (String name, String text)
|
||||
{
|
||||
if (StringUtil.IsEmpty(text)) return null;
|
||||
XmlDocument doc = Element.OwnerDocument;
|
||||
XmlElement child = (XmlElement)Element.AppendChild(doc.CreateElement(name));
|
||||
if (!StringUtil.IsEmpty(text))
|
||||
child.AppendChild(doc.CreateTextNode(text));
|
||||
return new SaMsXmlElement(child);
|
||||
}
|
||||
public SaMsXmlElement AppendNonBlankElement (SaXmlNamespace xmlNamespace, String name, String text)
|
||||
{
|
||||
if (StringUtil.IsEmpty(text)) return null;
|
||||
XmlDocument doc = Element.OwnerDocument;
|
||||
XmlElement child = (XmlElement)Element.AppendChild(doc.CreateElement(xmlNamespace.Prefix, name, xmlNamespace.Uri));
|
||||
if (!StringUtil.IsEmpty(text))
|
||||
child.AppendChild(doc.CreateTextNode(text));
|
||||
return new SaMsXmlElement(child);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Append element to node.</summary>
|
||||
public SaMsXmlElement AppendElement (SaMsXmlElement element)
|
||||
{
|
||||
// Import the node into the document before appending.
|
||||
XmlDocument doc = Element.OwnerDocument;
|
||||
XmlNode appendNode = doc.ImportNode(element.Element, true);
|
||||
XmlElement child = (XmlElement)Element.AppendChild(appendNode);
|
||||
return new SaMsXmlElement(child);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
|
||||
namespace Sarand.Net.Standard.Proc.Xml
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaMsXmlNode : SaErrorStateItem
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
internal XmlNode node;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
internal SaMsXmlNode (XmlNode node)
|
||||
{
|
||||
this.node = node;
|
||||
}
|
||||
protected override void Dispose (bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
node = null;
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
internal XmlDocument OwnerDocument { get { return node != null ? node.OwnerDocument : null; } }
|
||||
public String NamespaceURI { get { return node != null ? node.NamespaceURI : ""; } }
|
||||
public String Prefix { get { return node != null ? node.Prefix : ""; } }
|
||||
//public String Name { get { return node != null ? node.Name : ""; } }
|
||||
public String LocalName { get { return node != null ? node.LocalName : ""; } }
|
||||
public virtual bool Valid { get { return (node != null); } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// A t t r i b u t e s
|
||||
//-------------------------------------------------------------------
|
||||
public String GetAttributeValue (String attributeName)
|
||||
{
|
||||
if (StringUtil.IsEmpty(attributeName) || node == null) return "";
|
||||
foreach (XmlAttribute attribute in node.Attributes)
|
||||
{
|
||||
if (attribute.Name.EqualsCI(attributeName))
|
||||
return attribute.Value;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// T e x t
|
||||
//-------------------------------------------------------------------
|
||||
public String GetText ()
|
||||
{
|
||||
if (node == null) return "";
|
||||
foreach (XmlNode childNode in node.ChildNodes)
|
||||
{
|
||||
if (childNode.NodeType == XmlNodeType.Text || childNode.NodeType == XmlNodeType.CDATA)
|
||||
return childNode.Value;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// C h i l d N o d e s
|
||||
//-------------------------------------------------------------------
|
||||
public List<SaMsXmlNode> GetChildNodes (String name = "")
|
||||
{
|
||||
List<SaMsXmlNode> childNodes = new List<SaMsXmlNode>();
|
||||
if (node == null) return childNodes;
|
||||
foreach (XmlNode childNode in node.ChildNodes)
|
||||
{
|
||||
if (StringUtil.IsEmpty(name) || childNode.Name.EqualsCI(name))
|
||||
childNodes.Add(new SaMsXmlNode(childNode));
|
||||
}
|
||||
return childNodes;
|
||||
}
|
||||
public bool HasChildNode (String name)
|
||||
{
|
||||
if (node == null) return false;
|
||||
foreach (XmlNode childNode in node.ChildNodes)
|
||||
{
|
||||
if (StringUtil.IsEmpty(name) || childNode.Name.EqualsCI(name))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public SaMsXmlNode GetFirstChildNode (String name = "")
|
||||
{
|
||||
if (node == null) return new SaMsXmlNode(null);
|
||||
foreach (XmlNode childNode in node.ChildNodes)
|
||||
{
|
||||
if (StringUtil.IsEmpty(name) || childNode.Name.EqualsCI(name))
|
||||
return new SaMsXmlNode(childNode);
|
||||
}
|
||||
return new SaMsXmlNode(null);
|
||||
}
|
||||
public String GetChildText (String name, String defaultValue = "")
|
||||
{
|
||||
SaMsXmlNode childNode = GetFirstChildNode(name);
|
||||
if (childNode != null)
|
||||
return childNode.GetText();
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
public static class SaMsXmlNodeList
|
||||
{
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
|
||||
namespace Sarand.Net.Standard.Proc.Xml
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaXmlNamespace
|
||||
{
|
||||
public SaXmlNamespace (String prefix, String uri)
|
||||
{
|
||||
Prefix = prefix;
|
||||
Uri = uri;
|
||||
}
|
||||
public String Prefix { get; }
|
||||
public String Uri { get; }
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
public static class SaMsXmlUtil
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
public static Encoding DefaultEncoding { get; } = Encoding.UTF8;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Retrieve the Xml Declaration from the XML document.</summary>
|
||||
public static XmlDeclaration GetXmlDeclaration (this XmlDocument xmlDoc)
|
||||
{
|
||||
return xmlDoc.ChildNodes.OfType<XmlDeclaration>().FirstOrDefault();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Convert XML document to string.
|
||||
public static String GetXml (this XmlDocument xmlDoc, Encoding encoding = null)
|
||||
{
|
||||
// Ensure correct encoding for generated XML data.
|
||||
if (encoding == null) encoding = DefaultEncoding;
|
||||
XmlWriterSettings settings = new XmlWriterSettings() { Encoding = encoding };
|
||||
using (var stringWriter = new StringWriter())
|
||||
using (var xmlTextWriter = XmlWriter.Create(stringWriter, settings))
|
||||
{
|
||||
// Ensure that the document has the requested encoding in its XML declaration.
|
||||
XmlDeclaration xmlDeclaration = xmlDoc.GetXmlDeclaration();
|
||||
if (xmlDeclaration == null)
|
||||
{
|
||||
xmlDeclaration = xmlDoc.CreateXmlDeclaration("1.0", encoding.WebName, null);
|
||||
xmlDoc.InsertBefore(xmlDeclaration, xmlDoc.DocumentElement);
|
||||
}
|
||||
else xmlDeclaration.Encoding = encoding.WebName;
|
||||
// Write the document to String.
|
||||
xmlDoc.WriteTo(xmlTextWriter);
|
||||
xmlTextWriter.Flush();
|
||||
return stringWriter.GetStringBuilder().ToString();
|
||||
}
|
||||
}
|
||||
public static String FormatXml (this XmlDocument xmlDoc, Encoding encoding = null)
|
||||
{
|
||||
// Ensure correct encoding for generated XML data.
|
||||
if (encoding == null) encoding = DefaultEncoding;
|
||||
XmlWriterSettings settings = new XmlWriterSettings() { Encoding = encoding, Indent = true };
|
||||
using (MemoryStream memoryStream = new MemoryStream())
|
||||
using (var xmlTextWriter = new XmlTextWriter(memoryStream, encoding))
|
||||
{
|
||||
// XML output format.
|
||||
xmlTextWriter.Formatting = Formatting.Indented;
|
||||
// Ensure that the document has the requested encoding in its XML declaration.
|
||||
XmlDeclaration xmlDeclaration = xmlDoc.GetXmlDeclaration();
|
||||
if (xmlDeclaration == null)
|
||||
{
|
||||
xmlDeclaration = xmlDoc.CreateXmlDeclaration("1.0", encoding.WebName, null);
|
||||
xmlDoc.InsertBefore(xmlDeclaration, xmlDoc.DocumentElement);
|
||||
}
|
||||
else xmlDeclaration.Encoding = encoding.WebName;
|
||||
// Write the document to String.
|
||||
xmlDoc.WriteTo(xmlTextWriter);
|
||||
xmlTextWriter.Flush();
|
||||
memoryStream.Flush();
|
||||
memoryStream.Position = 0;
|
||||
using (StreamReader streamReader = new StreamReader(memoryStream))
|
||||
{
|
||||
return streamReader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Append element to node.
|
||||
public static XmlElement AppendElement (this XmlNode node, String name, String text = "")
|
||||
{
|
||||
XmlDocument doc = (node is XmlDocument ? node as XmlDocument : node.OwnerDocument);
|
||||
XmlElement child = (XmlElement)node.AppendChild(doc.CreateElement(name));
|
||||
if (!StringUtil.IsEmpty(text))
|
||||
child.AppendChild(doc.CreateTextNode(text));
|
||||
return child;
|
||||
}
|
||||
public static XmlElement AppendElement (this XmlNode node, SaXmlNamespace xmlNamespace, String name, String text = "")
|
||||
{
|
||||
XmlDocument doc = (node is XmlDocument ? node as XmlDocument : node.OwnerDocument);
|
||||
XmlElement child = (XmlElement)node.AppendChild(doc.CreateElement(xmlNamespace.Prefix, name, xmlNamespace.Uri));
|
||||
if (!StringUtil.IsEmpty(text))
|
||||
child.AppendChild(doc.CreateTextNode(text));
|
||||
return child;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get child text.
|
||||
public static String GetChildText (this XmlNode node, String name)
|
||||
{
|
||||
foreach (XmlNode child in node.ChildNodes)
|
||||
if (child.Name.EqualsCI(name))
|
||||
return child.InnerText;
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Sarand.Net.Standard.Proc.Zip
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaMsZipArchive : SaErrorStateItem
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private ZipArchive zipArchive;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaMsZipArchive ()
|
||||
{
|
||||
}
|
||||
protected override void Dispose (bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (zipArchive != null) zipArchive.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// A r c h i v e F i l e
|
||||
//-------------------------------------------------------------------
|
||||
public bool OpenArchive (String filePath, ZipArchiveMode mode = ZipArchiveMode.Read)
|
||||
{
|
||||
ClearErrorState();
|
||||
if (StringUtil.IsEmpty(filePath)) return SetErrorState("Filename must be supplied");
|
||||
CloseArchive();
|
||||
try
|
||||
{
|
||||
zipArchive = ZipFile.OpenRead(filePath);//, mode);
|
||||
ReadOnlyCollection<ZipArchiveEntry> entries = zipArchive.Entries;
|
||||
int entryCount = entries.Count;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn(GetType().Name + ".OpenArchive " + ExceptionUtil.GetLogMessage(exc));
|
||||
return SetErrorState(ExceptionUtil.GetErrorStateMessage(exc));
|
||||
}
|
||||
return !HasErrorState();
|
||||
}
|
||||
/// <summary>Open ZIP archive from data stream.</summary>
|
||||
public bool OpenArchive (Stream stream, ZipArchiveMode mode = ZipArchiveMode.Read, bool leaveOpen = true, Encoding entryNameEncoding = null)
|
||||
{
|
||||
ClearErrorState();
|
||||
if (entryNameEncoding == null) entryNameEncoding = Encoding.Default;
|
||||
CloseArchive();
|
||||
try
|
||||
{
|
||||
zipArchive = new ZipArchive(stream, mode, leaveOpen, entryNameEncoding);
|
||||
ReadOnlyCollection<ZipArchiveEntry> entries = zipArchive.Entries;
|
||||
int entryCount = entries.Count;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn(GetType().Name + ".OpenArchive " + ExceptionUtil.GetLogMessage(exc));
|
||||
return SetErrorState(ExceptionUtil.GetErrorStateMessage(exc));
|
||||
}
|
||||
return !HasErrorState();
|
||||
}
|
||||
public bool IsArchiveOpen ()
|
||||
{
|
||||
return (zipArchive != null);
|
||||
}
|
||||
/// <summary>Close eth ZIP archive.</summary>
|
||||
public bool CloseArchive ()
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
if (zipArchive != null) zipArchive.Dispose();
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SetErrorState(ExceptionUtil.GetErrorStateMessage(exc));
|
||||
SaLogger.Warn(GetType().Name + ".CloseArchive " + ExceptionUtil.GetLogMessage(exc));
|
||||
}
|
||||
zipArchive = null;
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// F i l e s
|
||||
//-------------------------------------------------------------------
|
||||
public MemoryStream ExtractFileToStream (String filename)
|
||||
{
|
||||
if (!IsArchiveOpen()) return null;
|
||||
foreach (ZipArchiveEntry entry in zipArchive.Entries)
|
||||
{
|
||||
//SaLogger.Debug(GetType().Name + ".GetFile Entry: " + entry.FullName);
|
||||
if (entry.FullName.EqualsCI(filename) || entry.Name.EqualsCI(filename))
|
||||
{
|
||||
using (Stream entryStream = entry.Open())
|
||||
{
|
||||
MemoryStream stream = new MemoryStream();
|
||||
entryStream.CopyTo(stream);
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<RootNamespace>Sarand.Net.Standard</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Proc\Word\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DocumentFormat.OpenXml" Version="2.12.3" />
|
||||
<PackageReference Include="NPOI" Version="2.5.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SacsStandardBase\SacsStandardBase.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user