我有一组大约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。我认为必须有一些方法来创建一个节点列表并根据随机数添加到它,然后从文档中选择最终的节点列表,一次删除所有以使其更快。这有意义吗?或者也许比我想的更有效率?
我很抱歉我的评论不会出现在评论中......我希望他们不会让事情变得混乱。
答案 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