1

我正在尝试从前面的元素中检索值。但是我尝试检索的值需要在某个位置之后和其他节点位置之前。我怎样才能做到这一点?

示例 XML:

<?xml version="1.0" encoding="UTF-8"?>
<actions>
    <action>
        <code>tr</code>
        <value>503</value>
    </action>
    <action>
        <code>co</code>
        <value>0</value>
    </action>
    <action>
        <code>cou</code>
        <value>0</value>
    </action>
    <action>
        <code>tr</code>
        <value>87</value>
    </action>
    <action>
        <code>st</code>
        <value>0</value>
    </action>
    <action>
        <code>wta</code>
        <value>0</value>
    </action>
    <action>
        <code>pi</code>
        <value>0</value>
    </action>
    <action>
        <code>tr</code>
        <value>64</value>
    </action>
    <action>
        <code>st</code>
        <value>0</value>
    </action>
    <action>
        <code>del</code>
        <value>0</value>
    </action>
    <action>
        <code>tr</code>
        <value>27</value>
    </action>
    <action>
        <code>wa</code>
        <value>0</value>
    </action>
    <action>
        <code>dec</code>
        <value>0</value>
    </action>
</actions>

当前 XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="xs fn">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:template match="/actions">
        <result>
            <!-- Loop through all action elements -->
            <xsl:for-each select="action">
                <!-- Display only the needed action in the result file -->
                <xsl:if test="code = 'co' or code = 'st' or code = 'dec' or code = 'pi' or code = 'del'">
                    <action>
                        <code>
                            <xsl:choose>
                                <xsl:when test="code = 'co'">1</xsl:when>
                                <xsl:when test="code = 'st'">5</xsl:when>
                                <xsl:when test="code = 'dec'">2</xsl:when>
                                <xsl:when test="code = 'pi'">3</xsl:when>
                                <xsl:when test="code = 'del'">4</xsl:when>
                            </xsl:choose>
                        </code>
                        <!-- Get some positions in variables -->
                        <xsl:variable name="previousPosition"><xsl:value-of select="position() - 1" /></xsl:variable>
                        <xsl:variable name="lastTRPosition"><xsl:value-of select="count((preceding::action[code = 'tr'])[last()]/preceding::action)+1" /></xsl:variable>
                        <xsl:variable name="currentPosition"><xsl:value-of select="position()" /></xsl:variable>
                        <!-- Should be the value of the preceding action element with code 'tr' (last occurence). But only use when between the last preceding action element with code 'tr' and the current node position NO known code is used ('co', 'st', 'dec', 'pi' or 'del') -->
                        <value>
                                    <xsl:choose>
                                        <xsl:when test="(preceding::action[code = 'tr']/value)[last()] != ''"> <!-- some work to do here -->
                                            <xsl:value-of select="round((preceding::action[code = 'tr']/value)[last()])" />
                                        </xsl:when>
                                        <xsl:otherwise>0</xsl:otherwise>
                                    </xsl:choose>
                        </value>
                    </action>
                </xsl:if>
            </xsl:for-each>
        </result>
    </xsl:template>
</xsl:stylesheet>

当前结果:

<?xml version="1.0" encoding="UTF-8"?>
<result>
    <action>
        <code>1</code>
        <value>503</value>
    </action>
    <action>
        <code>5</code>
        <value>87</value>
    </action>
    <action>
        <code>3</code>
        <value>87</value>
    </action>
    <action>
        <code>5</code>
        <value>64</value>
    </action>
    <action>
        <code>4</code>
        <value>64</value>
    </action>
    <action>
        <code>2</code>
        <value>27</value>
    </action>
</result>

想要的结果:

<?xml version="1.0" encoding="UTF-8"?>
<result>
    <action>
        <code>1</code>
        <value>503</value>
    </action>
    <action>
        <code>5</code>
        <value>87</value>
    </action>
    <action>
        <code>3</code>
        <value>0</value>
    </action>
    <action>
        <code>5</code>
        <value>64</value>
    </action>
    <action>
        <code>4</code>
        <value>0</value>
    </action>
    <action>
        <code>2</code>
        <value>27</value>
    </action>
</result>

这些变化以及为什么?

<action>
    <code>3</code>
    <value>87</value> <!-- should be 0 -->
</action>

这应该是 0。因为在action/code = 'tr'要写入结果的节点的最后一个位置和当前 position() 之间是一个已知代码“st”,它已经具有该值。

<action>
    <code>4</code>
    <value>64</value>
</action>

这应该是 0。因为在action/code = 'tr'要写入结果的节点的最后一个位置和当前 position() 之间是一个已知代码“st”,它已经具有该值。

我有点坚持在xsl:when. 有人可以帮忙吗?

4

2 回答 2

1

我建议与分组,group-starting-with然后使用>>运算符进行过滤。我还将映射作为参数并使用键来有效地映射,所以我得到了

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="xs fn">

    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:key name="code" match="code" use="@from"/>

    <xsl:param name="code-map">
      <code from="co" to="1"/>
      <code from="st" to="5"/>
      <code from="dec" to="2"/>
      <code from="pi" to="3"/>
      <code from="del" to="4"/>
    </xsl:param>

    <xsl:template match="/actions">
        <result>
            <xsl:for-each-group select="action" group-starting-with="action[code = 'tr']">
              <xsl:variable name="tr-head" select="."/>
              <xsl:apply-templates select="current-group()[self::action[code = $code-map/code/@from]]">
                <xsl:with-param name="tr" select="$tr-head"/>
              </xsl:apply-templates>
            </xsl:for-each-group>
        </result>
    </xsl:template>

    <xsl:template match="action">
      <xsl:param name="tr"/>
      <xsl:copy>
        <code>
          <xsl:value-of select="key('code', code, $code-map)/@to"/>
        </code>
        <value>
          <xsl:value-of 
            select="if (not(exists((current-group() except $tr) 
                                    [current() >> . and code = $code-map/code/@from])))
                    then $tr/value else 0"/>
        </value>
      </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

当我使用 Saxon 9.5 转换输入时

<?xml version="1.0" encoding="UTF-8"?>
<actions>
    <action>
        <code>tr</code>
        <value>503</value>
    </action>
    <action>
        <code>co</code>
        <value>0</value>
    </action>
    <action>
        <code>cou</code>
        <value>0</value>
    </action>
    <action>
        <code>tr</code>
        <value>87</value>
    </action>
    <action>
        <code>st</code>
        <value>0</value>
    </action>
    <action>
        <code>wta</code>
        <value>0</value>
    </action>
    <action>
        <code>pi</code>
        <value>0</value>
    </action>
    <action>
        <code>tr</code>
        <value>64</value>
    </action>
    <action>
        <code>st</code>
        <value>0</value>
    </action>
    <action>
        <code>del</code>
        <value>0</value>
    </action>
    <action>
        <code>tr</code>
        <value>27</value>
    </action>
    <action>
        <code>wa</code>
        <value>0</value>
    </action>
    <action>
        <code>dec</code>
        <value>0</value>
    </action>
</actions>

我得到了想要的结果

<result>
   <action>
      <code>1</code>
      <value>503</value>
   </action>
   <action>
      <code>5</code>
      <value>87</value>
   </action>
   <action>
      <code>3</code>
      <value>0</value>
   </action>
   <action>
      <code>5</code>
      <value>64</value>
   </action>
   <action>
      <code>4</code>
      <value>0</value>
   </action>
   <action>
      <code>2</code>
      <value>27</value>
   </action>
</result>
于 2013-05-28T14:15:06.187 回答
0

只是因为我说了,这里有一个 xslt-1.0 解决方案。

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

    <xsl:template match="action" />

    <xsl:template match="action [code = 'co' or code = 'st' or code = 'dec' or code = 'pi' or code = 'del']" >
        <result>
            <xsl:copy>
                <code>
                    <xsl:choose>
                        <xsl:when test="code = 'co'">1</xsl:when>
                        <xsl:when test="code = 'st'">5</xsl:when>
                        <xsl:when test="code = 'dec'">2</xsl:when>
                        <xsl:when test="code = 'pi'">3</xsl:when>
                        <xsl:when test="code = 'del'">4</xsl:when>
                    </xsl:choose>
                </code>
            <value>
                <xsl:variable name="ptr" select="preceding-sibling::action[code='tr'][1]"/>
                <xsl:variable name="trpos" select="count($ptr/preceding-sibling::action)"/>
                <xsl:variable name="pcode" select="preceding-sibling::action[code = 'co' or code = 'st' or code = 'dec' or code = 'pi' or code = 'del'][1]"/>
                <xsl:variable name="codepos" select="count($pcode/preceding-sibling::action)"/>
                <xsl:choose>
                    <xsl:when test="$trpos >= $codepos">
                        <xsl:value-of select="round($ptr/value)" />
                    </xsl:when>
                    <xsl:otherwise>0</xsl:otherwise>
                </xsl:choose>

            </value>
            </xsl:copy>
        </result>

    </xsl:template>
    <xsl:template match="/actions">
        <result>
            <xsl:apply-templates select="action" />
        </result>

    </xsl:template>
</xsl:stylesheet>
于 2013-05-28T14:57:20.330 回答