简体   繁体   English

单例/里程碑元素的XSLT转换

[英]XSLT transform of singleton/milestone elements

I'm looking for an elegant XSLT 1.0 or 2.0 solution to the following transform problem. 我正在寻找一种优雅的XSLT 1.0或2.0解决方案来解决以下转换问题。 I've simplified the markup below so "a" is the start milestone element, and "b" is the end milestone element. 我简化了下面的标记,因此“ a”是起始里程碑元素,而“ b”是终止里程碑元素。 Everything between the "a" and the "b" must be wrapped with element "c". “ a”和“ b”之间的所有内容都必须用元素“ c”包装。

Input: 输入:

<doc>
<line>Text text <a/>text<b/></line>
<line>Text <a/>text text</line>
<line>Text<b/> text <a/>text</line>
<line>Text text text</line>
<line>Text text<b/> text</line>
</doc>

Output: 输出:

<doc>
<line>Text text <c>text</c></line>
<line>Text <c>text text</c></line>
<line><c>Text</c> text <c>text</c></line>
<line><c>Text text text</c></line>
<line><c>Text text</c> text</line>
</doc>

In the real-world case, there are at least 5 variations each of the a/b/c elements to cater for. 在实际情况下,每个a / b / c元素至少要满足5种变化。 There are also tens of thousands of lines, many of which do not contain a/b or their variations. 还有成千上万的行,其中许多不包含a / b或它们的变体。 The real-world case also has a "sec" element wrapping groups of lines, where the a/b behaviour still needs to work through. 实际案例中还包含一个“ sec”元素,用于包装线组,其中a / b行为仍然需要解决。

Our initial solution involved the use of preceding::* but this obviously brings significant performance issues for large XML documents, so is not an acceptable solution. 我们最初的解决方案涉及到使用previous :: *,但这显然会给大型XML文档带来严重的性能问题,因此这不是可接受的解决方案。

Thanks to Michaely Kay for the inspiration. 感谢Michaely Kay的灵感。 Forgetting for a moment about the mechanics of wrapping the <c>..</c> elements, the correct algorithm as implemented in XSLT 3.0 appears to be: 暂时忘记包装<c> .. </ c>元素的机制,在XSLT 3.0中实现的正确算法似乎是:

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" />

<xsl:template match="/doc" >
    <xsl:copy>
        <xsl:iterate select="line">
            <xsl:param name="state">b</xsl:param>
            <xsl:variable name="lastState" select="local-name((a|b)[last()])"/>
            <xsl:variable name="nextState">
                <xsl:choose>
                    <xsl:when test="$lastState">
                        <xsl:value-of select="$lastState"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="$state"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:variable>

            <xsl:copy>
                <xsl:if test="$state = 'a'"><startC/></xsl:if>
                <xsl:apply-templates/>
                <xsl:if test="$nextState = 'a'"><endC/></xsl:if>                    
            </xsl:copy>

            <xsl:next-iteration>
                <xsl:with-param name="state" select="$nextState"/>
            </xsl:next-iteration>                                        
        </xsl:iterate>
    </xsl:copy>
</xsl:template>

<xsl:template match="a">
    <startC/>
</xsl:template>

<xsl:template match="b">
    <endC/>
</xsl:template>

Giving output: 提供输出:

<doc>
    <line>Text text <startC/>text<endC/></line>
    <line>Text <startC/>text text<endC/></line>
    <line><startC/>Text<endC/> text <startC/>text<endC/></line>
    <line><startC/>Text text text<endC/></line>
    <line><startC/>Text text<endC/> text</line>
</doc>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM