节点删除效率vba DOM

时间:2017-12-23 15:55:41

标签: xml excel vba xml-parsing

我有一组大约17,000个节点。我想选择一个随机数,然后删除具有该随机索引号的节点。目前我的作品。它是:

'some code to create a DOM as "xDoc",
'create a node object as "node",
'get total nodes as variable "total",
'get paths to a node as "xPath"

'Loop to reduce nodes to 1000
Do While total > 1000
    'some code to get a random number as variable "num"

    'initialize node object
    Set node = xDoc.SelectSingleNode(xPath & "[" & CStr(num) & "]”)

    'remove the node
    node.ParentNode.RemoveChild node

Loop

这需要太长时间。接近一个半小时,将来我的xml将呈指数级增长。它运行,正确删除节点只是sloooowwwwwwww。我认为必须有一些方法来创建一个节点列表并根据随机数添加到它,然后从文档中选择最终的节点列表,一次删除所有以使其更快。这有意义吗?或者也许比我想的更有效率?

我很抱歉我的评论不会出现在评论中......我希望他们不会让事情变得混乱。

2 个答案:

答案 0 :(得分:2)

可能的大部分成本是编译XPath表达式而不是实际删除节点。尝试使用参数编译一次XPath表达式的方法,然后使用不同的参数重复执行它。

但我认为在XSLT 3.0中有一个更好的方法:

<xsl:variable name="all" select="/*/*"/>
<xsl:variable name="retain" 
  select="random-number-generator()?permute($all)[position() le 1000]"/>
<xsl:copy-of select="$retain"/>

答案 1 :(得分:1)

考虑使用其MSXML库可以在Excel VBA中运行的XSLT 1.0。与{...}同步,XSLT是一种专用语言,用于转换XML文件,如删除节点。各种软件(SAS,Excel等)和编程语言(Java,Python等)通常都带有XSLT 1.0库。要使用XSLT 2.0和3.0,您需要在外部运行转换,可能是对Saxon or Exslt等专用处理器的命令行调用。

具体来说,XSLT将您的随机数接收到参数中,然后运行Identity Transform以按原样复制输入XML。最后,position()使用空模板删除特定节点。请务必将 mynode 更改为实际节点名称(没有完整的XPath)。

XSLT (另存为.xsl,一个特殊的xml文件)

<?xml version="1.0" ?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">  
  <xsl:output method="xml" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:param name="rand_num" />

  <!-- Identity Transform -->
  <xsl:template match="@*|node()">
     <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
     </xsl:copy>
  </xsl:template> 

  <!-- Remove Node by Position --> 
  <xsl:template match="mynode[position()=$rand_num]"/>

</xsl:stylesheet>

<强> VBA

Public Sub RunXSLT()
    ' REFERENCE Microsoft XML, v3.0 OR v6.0
    Dim xmlDoc As New MSXML2.DOMDocument60, xslDoc As New MSXML2.DOMDocument60, newDoc As New MSXML2.DOMDocument60

    'some code to get a random number as variable "num"

    ' LOAD INPUT XML
    xmlDoc.Load "C:\Path\To\Input.xml"
    xmlDoc.async = False

    ' LOAD XSLT SCRIPT AND PASS RANDOM NUMBER
    xslDoc.Load "C:\Path\To\XSLTScript.xsl"
    xslDoc.async = False
    xslDoc.addParameter "rand_num", num  

    ' TRANSFORM INPUT AND SAVE OUTPUT TO FILE
    xmlDoc.transformNodeToObject xslDoc, newDoc
    newDoc.Save "C:\Path\To\Output.xml"

    Set newDoc = Nothing: Set xslDoc = Nothing: Set xmlDoc = Nothing

End Sub