Quantcast
Channel: The Official Scripting Guys Forum! forum
Viewing all articles
Browse latest Browse all 15028

Powershell: Copying spreadsheet from memory to dataset.

$
0
0

I'm trying to use powershell to open a spreadsheet from a stream, copy into a dataset and then upload to SQL.  I'm having problems trying to figure out how to take the stream object and copy it into a dataset.  I've been trying to convert this C# code to powershell, but I'm having trouble figuring out how to do this.

static void Main(string[] args)
{
    DataTable dt = new DataTable();
    using (SpreadsheetDocument spreadSheetDocument = SpreadsheetDocument.Open(@"..\..\example.xlsx", false))
    {
        WorkbookPart workbookPart = spreadSheetDocument.WorkbookPart;
        IEnumerable<Sheet> sheets = spreadSheetDocument.WorkbookPart.Workbook.GetFirstChild<Sheets>().Elements<Sheet>();
        string relationshipId = sheets.First().Id.Value;
        WorksheetPart worksheetPart = (WorksheetPart)spreadSheetDocument.WorkbookPart.GetPartById(relationshipId);
        Worksheet workSheet = worksheetPart.Worksheet;
        SheetData sheetData = workSheet.GetFirstChild<SheetData>();
        IEnumerable<Row> rows = sheetData.Descendants<Row>();
        foreach (Cell cell in rows.ElementAt(0))
        {
            dt.Columns.Add(GetCellValue(spreadSheetDocument, cell));
        }
        foreach (Row row in rows) //this will also include your header row...
        {
            DataRow tempRow = dt.NewRow();
            for (int i = 0; i < row.Descendants<Cell>().Count(); i++)
            {
                tempRow[i] = GetCellValue(spreadSheetDocument, row.Descendants<Cell>().ElementAt(i-1));
            }
            dt.Rows.Add(tempRow);
        }
    }
    dt.Rows.RemoveAt(0); //...so i'm taking it out here.
}
public static string GetCellValue(SpreadsheetDocument document, Cell cell)
{
    SharedStringTablePart stringTablePart = document.WorkbookPart.SharedStringTablePart;
    string value = cell.CellValue.InnerXml;
    if (cell.DataType != null && cell.DataType.Value == CellValues.SharedString)
    {
        return stringTablePart.SharedStringTable.ChildElements[Int32.Parse(value)].InnerText;
    }
    else
    {
        return value;
    }
}

 This is what i've come up with so far, but I can't seem to get GenericMethod to function as expected.   I've attempted to use the Invoke-GenericMethod which is provided here. http://gallery.technet.microsoft.com/Invoke-Generic-Methods-bf7675af.   When I get the output of first $sheets I get back a collection object that includes the three sheets.

Function Excel-To-DataTable($spreadSheetDocument=$null) {
Begin{
    $dt = New-Object data.DataTable
}
Process{
        $workbookPart = $spreadSheetDocument.WorkbookPart;
        $sheets = Invoke-GenericMethod -InputObject $spreadSheetDocument.WorkbookPart.Workbook -MethodName GetFirstChild -GenericType DocumentFormat.OpenXml.Spreadsheet.Sheets
	$sheets = Invoke-GenericMethod -InputObject $sheets -MethodName Elements -GenericType DocumentFormat.OpenXml.Spreadsheet.Sheet
        $relationshipId = $sheets[0].Id.Value;
        $worksheetPart = $spreadSheetDocument.WorkbookPart.GetPartById($relationshipId);
        $workSheet = $worksheetPart.Worksheet;
	$sheetData = Invoke-GenericMethod -InputObject $worksheet -MethodName GetFirstChild -GenericType DocumentFormat.OpenXml.Spreadsheet.SheetData
        $rows = Invoke-GenericMethod -InputObject $sheetData[0] -MethodName Descendants -GenericType DocumentFormat.OpenXml.Spreadsheet.Row
        foreach ($cell in $rows.ElementAt(0))
        {
            $dt.Columns.Add(GetCellValue($spreadSheetDocument, $cell))
        }
        foreach ($row in $rows) #this will also include your header row...
        {
            $tempRow = $dt.NewRow();
            for (int $i -eq 0; $i -lt $row.DescendantsCell().Count(); $i++)
            {
                $tempRow[$i] = GetCellValue($spreadSheetDocument, $row.DescendantsCell().ElementAt($i-1));
            }
            $dt.Rows.Add($tempRow);
        }
    }
End{
    	$dt.Rows.RemoveAt(0)
	}
}
Function GetCellValue($document,$cell){
    $stringTablePart = $document.WorkbookPart.SharedStringTablePart;
    $value = $cell.CellValue.InnerXml;
    if ($cell.DataType -ne $null -and $cell.DataType.Value -eq $cell.CellValues.SharedString)
    {
        return $stringTablePart.SharedStringTable#.ChildElements[Int32.Parse(value)].InnerText;
    }
    else
    {
        return value;
    }
}
# Utilize .net WebClient class to dowload file.
$url = "http://testsite/TestSpreadSheet.xlsx"
$wc = new-object System.Net.WebClient
$wc.UseDefaultCredentials = $true
$ByteArray = $wc.DownloadData($url)
# Store in .net memory stream.
# unary comma operator to suppress the default behavior of unraveling of  
# the array before passing it to the constructor.
$memStream = New-Object System.IO.MemoryStream(,$ByteArray)
# Load assembly into memory and load it.
$file='C:\Program Files\Open XML SDK\V2.5\lib\DocumentFormat.OpenXml.dll'
$fileStream = ([System.IO.FileInfo] (Get-Item $file)).OpenRead();
$assemblyBytes = new-object byte[] $fileStream.Length
$null= $fileStream.Read($assemblyBytes, 0, $fileStream.Length);
$fileStream.Close();
$assemblyLoaded = [System.Reflection.Assembly]::Load($assemblyBytes);
#Use OpenXML to open spreadsheet from memory.
$isEditable = $false
$spreadsheet = [DocumentFormat.OpenXML.Packaging.SpreadsheetDocument]::Open($MemStream,$isEditable)
Excel-To-DataTable $spreadsheet
$spreadsheet.Close
Your guidance is greatly appreciated!


Viewing all articles
Browse latest Browse all 15028

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>