对于XSLT,我有一个我希望的简单问题。我有一些平坦的XML文件,这些文件可能很大(例如7MB),我需要使“更加层次”。例如,平坦的XML可能看起来像这样:

<D0011>
    <b/>
    <c/>
    <d/>
    <e/>
    <b/>
    ....
    ....
</D0011>

它最终应该看起来像这样:

<D0011>
  <b>
    <c/>
    <d/>
    <e/>
  </b>
  <b>
 ....
 ....
</D0011>

我为此有一个工作XSLT,它实际上获得了所有B元素的nodeset,然后使用“后串联”轴来获取节点的nodeset,遵循当前的B节点(即sufter。sufter。Suster。siplobling ::***) [位置()= $ nodepos])。然后,递归用于将兄弟姐妹添加到结果树中,直到找到另一个B元素(当然,我已经对其进行了参数,以使其更通用)。

我还有一个解决方案,该解决方案仅发送下一个B节点的XML位置,然后通过A *[position()= $ nodepos]选择一个接一个接一个的节点(使用递归)。

问题在于,执行转换的时间随着XML文件的大小而增加。使用XML间谍来研究它,似乎是“ suster sibling”和“ position()=”需要两种方法中的时间。

我真正需要的是一种限制上述选择中的节点数量的方法,因此进行更少的比较:每次测试位置时,测试了nodeset中的每个节点以查看其位置是否正确。有没有办法做到这一点 ?还有其他建议吗?

谢谢,

麦克风

有帮助吗?

解决方案

是的,有一种方法可以更有效地做到这一点:查看 Muenchian分组. 。如果看过这一点,您需要更多的详细信息帮助,请告诉我们。您需要的关键是:

<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>

其他提示

<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>

这是细粒度的曲折模式:

<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>
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top