使用XSLT或通过将XML操作为String将大型XML文件包装元素放入标记中



我有一个相当大的XML文件,大约3-4 MB,我需要将某些元素封装在标记中。我的Xml具有以下结构:

<body>
<p></p>
<p>
<sectPr></sectPr>
</p>
<p></p>
<p></p>
<tbl></tbl>
<p>
<sectPr></sectPr>
</p>
</body>

当然,所有的ptbl元素都会在body中重复,直到文件结束(上面介绍的每个元素都会有子元素——为了简单起见,我只是把它们去掉了)。作为估计,我将在body内具有大约70个包含sectPr的元素,不一定按照我上面描述的顺序。

我想做的是将从包含sectPr的元素开始到下一个包含sectPr的元素的所有元素包装到另一个标签中。因此,我的XML应该是这样的:

<body>
<p></p>
<myTag>
<p>
<sectPr></sectPr>
</p>
<p></p>
<p></p>
<tbl></tbl>
</myTag>
<myTag>
<p>
<sectPr></sectPr>
</p>
</myTag> 
</body>

此外,另一项要求是操作必须在40秒内完成。

我的问题是:你认为使用XSLT可以实现这个结果吗?如果是这样的话,请提供一个关于我如何做到这一点的简短描述,或者你认为最好将XML文件读取为字符串,然后通过操纵字符串来添加标记?

另外,作为编程语言,我使用的是Visual Basic。

提前谢谢。

另一个要求是操作必须在40以下执行秒。

性能在很大程度上取决于所使用的特定处理器。如果您使用的是MSXML,那么在这种情况下使用所谓的"同级递归"可能会从中受益匪浅——正如Dimitre Novatchev最近所展示的那样。

尝试:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/body">
<xsl:copy>
<!-- start a "chain" for each leading node  -->
<xsl:apply-templates select="*[1] | *[sectPr]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="body/*[sectPr]" priority="1">
<myTag>
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
<!-- call the next sibling in chain  -->
<xsl:apply-templates select="following-sibling::*[1][not(sectPr)]"/>
</myTag>
</xsl:template>
<xsl:template match="body/*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
<!-- call the next sibling in chain  -->
<xsl:apply-templates select="following-sibling::*[1][not(sectPr)]"/>
</xsl:template>
</xsl:stylesheet>

这个样式表就可以了。虽然使用键的效率更高,但我不确定你的文件需要多少时间。

<xsl:stylesheet  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- key to select following-sibling of current element containing sectPr, and preceding-sibling of the next element containing sectPr -->
<xsl:key name="following-sectPr" match="*[not(self::*[sectPr])]" use="generate-id(preceding-sibling::*[sectPr][1])"/>
<!-- Identity transform template to copy nodes and attributes -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<!-- template to match the elements containing sectPr and add myTag to them and the elements matching the above declared key -->
<xsl:template match="*[sectPr]">
<myTag>
<xsl:apply-templates select="current() | key('following-sectPr', generate-id())" mode="copy"/>
</myTag>
</xsl:template>
<!-- template to do nothing for the elements with no sectPr but having a preceding-sibling elment containing sectPr -->
<xsl:template match="*[not(sectPr) and preceding-sibling::*[sectPr]]"/>
<!-- template to copy elements pushed by the template matching *[sectPr] -->
<xsl:template match="*" mode="copy">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

最新更新