相对较新的XSLT,我希望这是一个简单的问题。我有一些扁平的XML文件,这些文件可能非常大(例如7MB),我需要让它更“层次化”。例如,平面XML可能如下所示:
<D0011>
<b/>
<c/>
<d/>
<e/>
<b/>
....
....
</D0011>
它应该看起来像这样:
<D0011>
<b>
<c/>
<d/>
<e/>
</b>
<b>
....
....
</D0011>
我有一个工作的XSLT,它实际上获取了所有b元素的节点集,然后使用'follow-sibling'轴来获取当前b节点之后的节点的节点集(即.sree-sibling) :: * [位置()= $ nodePos])。然后使用递归将兄弟姐妹添加到结果树中,直到找到另一个b元素(我当然已将其参数化,以使其更通用)。
我还有一个解决方案,它只是在下一个b节点的XML中发送位置,然后通过* [position()= $ nodePos]选择在那个节点之后选择节点(使用递归)。
问题是执行转换的时间与XML文件的大小不可接受地增加。使用XML Spy调查它似乎是'follow-sibling'和'position()='花费时间在两个相应的方法中。
我真正需要的是一种限制上述选择中节点数量的方法,因此执行的比较较少:每次测试位置时,都会测试节点集中的每个节点以查看其位置是否正确。有没有办法做到这一点 ?还有其他建议吗?
谢谢,
麦克
答案 0 :(得分:1)
是的,有一种方法可以更有效地做到这一点:见Muenchian grouping。如果看了这个,你需要更多的帮助细节,请告诉我们。你需要的关键是:
<xsl:key name="elements-by-group" match="*[not(self::b)]"
use="generate-id(preceding-sibling::b[1])" />
然后,您可以迭代<b>
个元素,对于每个元素,使用key('elements-by-group', generate-id())
来获取紧跟<b>
的元素。
“使XML更加层次化”的任务有时被称为向上转换,您的场景就是它的经典案例。您可能知道,XSLT 2.0具有非常有用的分组功能,比Muenchian方法更易于使用。
在您的情况下,听起来您会使用<xsl:for-each-group group-starting-with="b" />
或参数化元素名称<xsl:for-each-group group-starting-with="*[local-name() = 'b']" />
。但也许您已经考虑过了,并且无法在您的环境中使用XSLT 2.0。
<强>更新强>
响应参数化请求,这是一种没有密钥的方法。 请注意,它可能会慢得多,具体取决于您的XSLT处理器。
<xsl:template match="D0011">
<xsl:for-each select="*[local-name() = $sep]">
<xsl:copy>
<xsl:copy-of select="following-sibling::*[not(local-name() = $sep)
and generate-id(preceding-sibling::*[local-name() = $sep][1]) =
generate-id(current())]" />
</xsl:copy>
</xsl:for-each>
</xsl:template>
如评论中所述,您可以通过定义几个不同的密钥来保持密钥的性能优势,每个密钥对应于参数的每个可能值。然后,您可以使用<xsl:choose>
选择要使用的密钥。
更新2:
要使基于/*/*[2]
定义组起始元素,而不是基于参数,请使用
<xsl:key name="elements-by-group"
match="*[not(local-name(.) = local-name(/*/*[2]))]"
use="generate-id(preceding-sibling::*
[local-name(.) = local-name(/*/*[2])][1])" />
<xsl:template match="D0011">
<xsl:for-each select="*[local-name(.) = local-name(../*[2])]">
<xsl:copy>
<xsl:copy-of select="key('elements-by-group', generate-id())"/>
</xsl:copy>
</xsl:for-each>
</xsl:template>
答案 1 :(得分:1)
<xsl:key name="k1" match="D0011/*[not(self::b)]" use="generate-id(preceding-sibling::b[1])"/>
<xsl:template match="D0011">
<xsl:copy>
<xsl:apply-templates select="b"/>
</xsl:copy>
</xsl:template>
<xsl:template match="D0011/b">
<xsl:copy>
<xsl:copy-of select="key('k1', generate-id())"/>
</xsl:copy>
</xsl:template>
答案 2 :(得分:0)
这是细粒度的trasversal模式:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()[1]|@*"/>
</xsl:copy>
<xsl:apply-templates select="following-sibling::node()[1]"/>
</xsl:template>
<xsl:template match="b[1]" name="group">
<xsl:copy>
<xsl:apply-templates select="following-sibling::node()[1]"/>
</xsl:copy>
<xsl:apply-templates select="following-sibling::b[1]" mode="group"/>
</xsl:template>
<xsl:template match="b[position()!=1]"/>
<xsl:template match="b" mode="group">
<xsl:call-template name="group"/>
</xsl:template>
</xsl:stylesheet>
输出:
<D0011>
<b>
<c></c>
<d></d>
<e></e>
</b>
<b>
....
....
</b>
</D0011>