1

我是这个 XSLT 的新手,我不知道怎么做:

这是我开始的 xml 的一个片段:

<Article>    
<Bullettext>10,00 </Bullettext>  
<Bullettext>8,00 </Bullettext>    
</Article>  
<Article>  
<something>some text</something>  
</Article>  
<Article>  
<Corpsdetexte>Bulgaria</Corpsdetexte>  
<Bullettext>15,0 </Bullettext>  
<Bullettext>10,0 </Bullettext>  
</Article> ` 

这就是我想要的输出:

<LIST>  
<ITEM>12,00 </ITEM>  
<ITEM>10,00 </ITEM>  
<ITEM>8,00 </ITEM>  
</LIST>  
<P>  
<something>some text</something>  
</P>  

<P>  
<Corpsdetexte>Bulgaria</Corpsdetexte>  
</P>  
<LIST>  
<ITEM>15,0 </ITEM>  
<ITEM>10,0 </ITEM>  
</LIST>  

有任何想法吗??

4

4 回答 4

5

根据您对 Rubens Farias 的回答的评论(实际上,您应该编辑您的问题以包括在内),您似乎想要一种通用方法将任何一组相邻BulletText元素转换为列表。这给我们带来了两个问题:我们如何找到这样的组,找到它们后,我们如何将它们转换为列表?

要找到一个组,我们需要查找BulletText其前一个兄弟元素不是元素的所有BulletText元素。每一个都开始一个组,这些是我们将要转换为列表的元素。所以我们要做的第一件事是创建一个 XPath 表达式来找到它们:

BulletText[not(preceding-sibling::*[1][name()='BulletText'])]

如果您查看该 XPath 表达式中的谓词,它正在做我所说的我们需要做的事情:BulletText如果它的第一个前面的兄弟 ( preceding-sibling::*[1]) 的名称不是BulletText. 请注意,如果元素没有前面的兄弟元素,则此表达式仍将匹配它。

所以现在我们可以创建一个模板来匹配这些起始组元素。我们在这个模板中放了什么?我们要将这些元素转换为LIST元素,所以模板开始看起来像:

<LIST>
   ...
</LIST>

很容易。但是我们如何找到要填充该列表的元素呢?我们必须处理两种情况。

第一个很简单:如果以下所有兄弟姐妹都是BulletText元素,我们希望使用此元素及其所有以下兄弟姐妹填充列表。

第二个更难。如果后面的兄弟不是BulletText元素,我们希望我们的列表是当前元素父元素的所有子元素,从当前元素开始,在停止元素之前结束。这是一个案例,我们需要使用count()函数来计算开始和结束索引,以及position()找到每个元素的位置的函数。

完成的模板如下所示:

<xsl:template match="BulletText[not(preceding-sibling::*[1][name()='BulletText'])]">
  <!-- find the element that we want to stop at -->
  <xsl:variable name="stop" select="./following-sibling::*[name() != 'BulletText'][1]"/>
  <LIST>
    <xsl:choose>
      <!-- first, the simple case:  there's no element we have to stop at -->
      <xsl:when test="not($stop)">
        <xsl:apply-templates select="." mode="item"/>
        <xsl:apply-templates select="./following-sibling::BulletText" mode="item"/>
      </xsl:when>
      <!-- transform all elements between the start and stop index into items -->
      <xsl:otherwise>
        <xsl:variable name="start_index" select="count(preceding-sibling::*) + 1"/>
        <xsl:variable name="stop_index" select="count($stop/preceding-sibling::*)"/>
        <xsl:apply-templates select="../*[position() &gt;= $start_index 
                                      and position() &lt;= $stop_index]"
                             mode="item"/>
      </xsl:otherwise>
    </xsl:choose>
  </LIST>
</xsl:template>

您需要另外两个模板。将BulletText元素转换为项目 - 我们mode在这里使用,以便我们可以将其应用于BulletText元素而无需调用我们当前使用的模板:

<xsl:template match="BulletText" mode="item">
   <ITEM>
      <xsl:value-of select="."/>
   </ITEM>
</xsl:template>

然后你还需要一个模板来防止我们的第一个模板BulletText匹配的元素生成任何输出(因为如果我们使用恒等变换,如果我们不使用它们只会被复制):

<xsl:template match='BulletText'/>

由于 XSLT 模板优先规则的魔力BulletText,两个模板匹配的任何元素都将被第一个转换,而这个将捕获其余的。

只需将这三个模板添加到身份转换即可。

于 2010-01-14T20:45:56.230 回答
1

我认为您正在寻找有条件的 deep-copy

这是针对您的情况重写的上述链接中的代码:

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

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>

    <!-- nodes with Bullettext children -->
    <xsl:template match="*[Bullettext]">
        <!-- for every child -->
        <xsl:copy>
            <xsl:for-each select="*">
                <!-- if child is a Bullettext and it has a Bullettext before it, don't copy it (it has already been copied) -->
                <xsl:if test="not(local-name(.) = 'Bullettext' and local-name(./preceding-sibling::*[1]) = 'Bullettext')">
                    <xsl:choose>
                        <xsl:when test="local-name(.) = 'Bullettext'">
                            <!-- copy all Bullettext children adjacent to this one and each other -->
                            <LIST>
                                <xsl:call-template name="get-all-adjacent-siblings">
                                    <xsl:with-param name="sibling-before" select="." />
                                </xsl:call-template>
                            </LIST>
                        </xsl:when>
                        <xsl:otherwise>
                            <!-- copy non-Bullettext child -->
                            <xsl:apply-templates select="." />
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:if>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>

    <xsl:template name="get-all-adjacent-siblings">
        <xsl:param name="sibling-before" />
        <!-- return me -->
        <xsl:copy>
            <xsl:value-of select="$sibling-before" />
        </xsl:copy>
        <!-- return my adjacent Bullettext siblings below me -->
        <xsl:if test="local-name($sibling-before/following-sibling::*[1]) = 'Bullettext'">
            <xsl:call-template name="get-all-adjacent-siblings">
                <xsl:with-param name="sibling-before" select="$sibling-before/following-sibling::*[1]" />
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>

我使用的输入是:

<?xml version="1.0" encoding="utf-8"?>
<Articles>
    <Article>
        <Bullettext>10,00 </Bullettext>
        <Bullettext>8,00 </Bullettext>
    </Article>
    <Article>
        <something>some text</something>
    </Article>
    <Article>
        <Corpsdetexte>Bulgaria</Corpsdetexte>
        <deeper>
            <before>dogs</before>
            <Bullettext>15,0 </Bullettext>
            <Bullettext>10,0 </Bullettext>
            <middle>cats</middle>
            <Bullettext>25,0 </Bullettext>
            <Bullettext>20,0 </Bullettext>
            <after>cows</after>
        </deeper>
    </Article>
</Articles>

它给了我:

<?xml version="1.0" encoding="UTF-8"?>
<Articles>
    <Article>
        <LIST>
            <Bullettext>10,00 </Bullettext>
            <Bullettext>8,00 </Bullettext>
        </LIST>
    </Article>
    <Article>
        <something>some text</something>
    </Article>
    <Article>
        <Corpsdetexte>Bulgaria</Corpsdetexte>
        <deeper>
            <before>dogs</before>
            <LIST>
                <Bullettext>15,0 </Bullettext>
                <Bullettext>10,0 </Bullettext>
            </LIST>
            <middle>cats</middle>
            <LIST>
                <Bullettext>25,0 </Bullettext>
                <Bullettext>20,0 </Bullettext>
            </LIST>
            <after>cows</after>
        </deeper>
    </Article>
</Articles>

如果您想进行其他转换(例如<p></p>在同一个样式表中添加 s),这有点混乱,但是如果您使用两个样式表进行两步转换,第一个执行上面的条件深度复制,然后第二个使用结果进行主要转换首先,你应该很高兴。

于 2010-01-14T13:38:08.573 回答
1

使用三个模板对兄弟姐妹进行分组

尽管这个问题目前有几个可行的答案,但您实际上可以使用三个模板和标识非常轻松地对兄弟姐妹进行分组。

首先,您需要一个模板来删除所有节点并设置其优先级,以便我们可以用另一个模板覆盖它。

<xsl:template match="Bullettext" priority="1"/>

然后,定义一个模板来匹配其前面没有的任何节点,并为其分配更高的优先级。此模板将注入组,然后开始以不同的模式复制节点。

<xsl:template match="Bullettext[not(preceding-sibling::*[1][self::Bullettext])]" priority="2">
  <LIST>
    <xsl:apply-templates select="." mode="bullet-list"/>
  </LIST>
</xsl:template>

最后,定义一个尾递归模板来处理被分组的项目。

<xsl:template match="Bullettext" mode="bullet-list">
  <ITEM>
    <xsl:apply-templates select="@*|node()"/>
  </ITEM>
  <xsl:apply-templates select="following-sibling::*[1][self::Bullettext]" mode="bullet-list"/>
</xsl:template>

这是一个完整的样式表,它将对示例中的 Bullettext 元素进行分组:

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

  <!-- Identity -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
  </xsl:template>

  <!-- Removes the Bullettext elements in the default mode. -->
  <xsl:template match="Bullettext" priority="1" />

  <!-- Creates the LIST elements around the removed Bullettext elements. -->
  <xsl:template match="Bullettext[not(preceding-sibling::*[1][self::Bullettext])]" priority="2">
    <LIST>
      <xsl:apply-templates select="." mode="bullet-list" />
    </LIST>
  </xsl:template>

  <!-- Converts sequential Bullettext elements into ITEM elements. -->
  <xsl:template match="Bullettext" mode="bullet-list">
    <ITEM>
      <xsl:apply-templates select="@*|node()" />
    </ITEM>
    <xsl:apply-templates select="following-sibling::*[1][self::Bullettext]" mode="bullet-list" />
  </xsl:template>

</xsl:stylesheet>
于 2012-12-06T09:12:08.527 回答
0

尝试这样的事情:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/Articles">
    <LIST>
      <xsl:for-each select="Article[1]/Bullettext">
        <ITEM>
          <xsl:value-of select="." />
        </ITEM>
      </xsl:for-each>
    </LIST>

    <p>
      <something>
        <xsl:value-of select="Article[2]/something" />
      </something>
    </p>

    <p>
      <Corpsdetexte>
        <xsl:value-of select="Article[3]/Corpsdetexte" />
      </Corpsdetexte>
    </p>

    <LIST>
      <xsl:for-each select="Article[4]/Bullettext">
        <ITEM>
          <xsl:value-of select="." />
        </ITEM>
      </xsl:for-each>
    </LIST>
  </xsl:template>
</xsl:stylesheet>
于 2010-01-14T11:21:58.453 回答