2013-03-08 69 views
0

我有加載XML文檔的代碼,執行$xmlDoc.SelectNodes($XPath),然後foreach($node in $nodes)將XML作爲字符串戳到表中。閱讀大型XML文檔以在Powershell中生成XML節點數組?

此代碼適用於CA的文件。 100KB有10條記錄。

但是,我有一個文件是ca. 100MB和約。 50k記錄和代碼只是掛在$xmlDoc =[xml](gc $xmlpath)(並使用所有可用的系統內存)。沒有首先解析整個XML文檔,是否有更好的方法來生成我的數組$nodes

# Loads xml document 
$xmlpath = $filepath 
$xmlDoc =[xml](gc $xmlpath) 
$nodes = $xmlDoc.SelectNodes('//root') #One element per record in SQL 

... 

$SqlQuery = @" 
INSERT INTO {0} VALUES ({1}) 
"@ 

.... 

foreach($node in $nodes) 
{ 
$StringWriter = New-Object System.IO.StringWriter 
$XmlWriter = New-Object System.XMl.XmlTextWriter $StringWriter 
$XmlWriter.Formatting = "None" 
$XmlWriter.Flush() 
$StringWriter.Flush() 
$node.WriteTo($XmlWriter) 
#data content (for this quote) 
$Pxml = "`'"+$StringWriter.ToString()+"`'" 

#Write to database 
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand 
$SqlCmd.CommandText = [string]::Format($sqlquery, $tableName, $Pxml) 
$SqlCmd.Connection = $SqlConnection 
$SqlCmd.ExecuteScalar() 
} 

XML文檔具有結構:

<xml> 
    <root> 
    ... 
    </root> 
    <root> 
    ... 
    </root> 
</xml> 

並將所得字符串形式:

<root> 
... 
</root> 

回答

1

使用this link作爲基礎,請嘗試下面的代碼。 $object應該包含你的根對象

$object= @() 
type "$filepath" | %{ 
    if($_.trim() -eq "<root>") { 
    $object= @() 
    $object+= $_ 
    } 
    elseif($_.trim() -eq "</root>"){ 
    $object+= $_ 
    #call the code within your foreach($node in $nodes) {} section here 
    } else { 
    $object+= $_ 
    } 
} 
+0

這產生了所需的結果幾乎直接出罐。 – JustinJDavies 2013-03-08 16:31:10

1

據我所知,XML解析需要完整的文件是在記憶。嘗試使用更高效的.Net方法來閱讀內容。以下內容應該運行得更快並且可以使用更少的內存,因爲它將內容保存爲字符串數組而不是像Get-Content這樣的字符串對象數組。

# Loads xml document 

# Get aboslute path 
$xmlpath = (Resolve-Path $filepath).Path 
# Get xml 
$xmlDoc = [xml]([IO.File]::ReadAllLines($xmlpath)) 

更快的解決辦法是放棄鑄造到XML的文檔,只是解析它爲純文本。我仍然會避免Get-Content,因爲它很慢。像這樣的東西可以工作:

# Get aboslute path 
$xmlpath = (Resolve-Path $filepath).Path 

# Get streamreader 
$reader = [io.file]::OpenText($xmlpath) 
$currentroot = @() 

# Read every line 
while (($line = $reader.ReadLine()) -ne $null) { 
    if ($line.Trim() -eq "<root>") { 
     $currentroot.Clear() 
     $currentroot += $line 
    } else if ($line.Trim() -eq "</root>") { 
     $currentroot += $line 

     #process root element (by extracting the info from the strings in $currentroot) 

     $currentroot.Clear() 
    } else { 
     $currentroot += $line 
    } 
}