我有加载XML文档的代码,执行$xmlDoc.SelectNodes($XPath)
然后foreach($node in $nodes)
将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>
答案 0 :(得分: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
}
}
答案 1 :(得分: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+= $_
}
}