XSL迭代更新该值

时间:2014-04-03 21:11:09

标签: xml xslt

我对XSL很新,所以我很感激任何帮助。这是我的一个示例xml:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <data>
     <element>
        <e>BenefitUsed</e>
        <p>
           <BenefitType>Fuel</BenefitType>
           <QuantityTotal>3</QuantityTotal>
           <QuantityUsed>1</QuantityUsed>
           <PlayerLevel>5</PlayerLevel>
        </p>
        <t>1395922443994</t>
        <ts>336761474</ts>
     </element>
     <element>
        <e>StartMission</e>
        <p>
           <AvatarID>123</AvatarID>
           <MissionID>2785</MissionID>
           <MissionType>TaxiBadge</MissionType>
        </p>
        <t>1395922445517</t>
        <ts>336762997</ts>
     </element>
     <element>
        <e>EndMission</e>
        <p>
           <AvatarID>123</AvatarID>
           <BestAttempt>0</BestAttempt>
           <BoostsUsed>0</BoostsUsed>
           <PlayerLevel>6</PlayerLevel>
        </p>
        <t>1395922445576</t>
        <ts>336763056</ts>
     </element>
     <element>
        <e>BenefitUsed</e>
        <p>
           <BenefitType>Fuel</BenefitType>
           <QuantityTotal>2</QuantityTotal>
           <QuantityUsed>1</QuantityUsed>
           <PlayerLevel>7</PlayerLevel>
        </p>
        <t>1395922443994</t>
        <ts>336761474</ts>
     </element>
   </data>
</root>

我想迭代元素并输出它的名称和当前玩家等级(标记"p/PlayerLevel")。我有一个播放器级别的默认值(设置为-1),如果元素包含标签"p/PlayerLevel",则应该更改,否则播放器级别保持不变。

所以,这是我的xsl文件:

<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method='text' omit-xml-declaration="yes"/>

<xsl:param name="level" select="-1"/>

<xsl:template name="mVarUpdate">
    <xsl:param name="level">
        <xsl:choose>
            <xsl:when test="p/PlayerLevel">
            <xsl:value-of select="p/PlayerLevel"/>
            </xsl:when>
        </xsl:choose>
    </xsl:param>
</xsl:template>

<xsl:template match="/">
    <xsl:for-each select="root/data/element">
        <xsl:call-template name="mEventHandler"/>           
     </xsl:for-each>
    </xsl:template>

 <xsl:template name="mEventHandler">
    <xsl:call-template name="mVarUpdate">
        <xsl:with-param name="level" />
    </xsl:call-template>
    <xsl:choose>
        <xsl:when test="e='BenefitUsed'">
            <xsl:call-template name="mBenefitUsed"/>
        </xsl:when>
        <xsl:when test="e='StartMission'">
            <xsl:call-template name="mStartMission"/>
        </xsl:when>
        <xsl:when test="e='EndMission'">
            <xsl:call-template name="mEndMission"/>
        </xsl:when>
    </xsl:choose>
</xsl:template>

<xsl:template name="mBenefitUsed">
    <xsl:text>This is BenefitUsed event</xsl:text>
    <xsl:text>,</xsl:text>
    <xsl:copy-of select="$level"/>
    <xsl:text>,</xsl:text>
    <xsl:text>Some other data related to event BenefitUsed</xsl:text>
    <xsl:text>&#10;</xsl:text>
</xsl:template>

<xsl:template name="mStartMission">
    <xsl:text>This is StartMission event</xsl:text>
    <xsl:text>,</xsl:text>
    <xsl:copy-of select="$level"/>
    <xsl:text>,</xsl:text>
    <xsl:text>Some other data related to event StartMission</xsl:text>
    <xsl:text>&#10;</xsl:text>
</xsl:template>

<xsl:template name="mEndMission">
    <xsl:text>This is EndMission event</xsl:text>
    <xsl:text>,</xsl:text>
    <xsl:copy-of select="$level"/>
    <xsl:text>,</xsl:text>
    <xsl:text>Some other data related to event EndMission</xsl:text>
    <xsl:text>&#10;</xsl:text>
</xsl:template> 
 </xsl:stylesheet>

它运作正常并产生以下内容:

    This is BenefitUsed event,-1,Some other data related to event BenefitUsed
    This is StartMission event,-1,Some other data related to event StartMission
    This is EndMission event,-1,Some other data related to event EndMission
    This is BenefitUsed event,-1,Some other data related to event BenefitUsed

但理想情况下我想:

    This is BenefitUsed event,5,Some other data related to event BenefitUsed
    This is StartMission event,5,Some other data related to event StartMission
    This is EndMission event,6,Some other data related to event EndMission
    This is BenefitUsed event,7,Some other data related to event BenefitUsed

我可以以某种方式迭代地改变这个值吗?

P.S。我知道在没有很多模板的情况下编写XSL会更容易,但是基于它的名称的每个元素将来会以不同的方式处理。 感谢您的帮助

2 个答案:

答案 0 :(得分:1)

在XSLT中,变量(和参数)是不可变的,因此最初设置后不能更改。您的 mVarUpdate 模板正在进行的是在模板范围内本地设置参数的值(它与全局定义的参数不同)。

现在,如果你想找到一个元素的“玩家级别”,你可以使用这样的命名元素:

<xsl:template name="level">
   <xsl:choose>
      <xsl:when test="p/PlayerLevel"><xsl:value-of select="p/PlayerLevel" /></xsl:when>
      <xsl:otherwise><xsl:value-of select="preceding-sibling::*/p/PlayerLevel[1]" /></xsl:otherwise>
   </xsl:choose>
</xsl:template>

(即检查当前元素是否有一个级别。如果不是,那么先得到第一个兄弟姐妹)

然后,您可以执行<xsl:copy-of select="$level"/>

,而不是<xsl:call-template name="level"/>

现在,您也正确地说“在没有很多模板的情况下编写XSL会更容易”。您可以做的是使用单个通用模板来匹配任何元素元素,但您仍然可以使用更具体的模板匹配具有特定名称的其他元素元素。

例如,尝试以下XSLT

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <xsl:output method="text" omit-xml-declaration="yes"/>

   <xsl:template name="level">
      <xsl:choose>
         <xsl:when test="p/PlayerLevel"><xsl:value-of select="p/PlayerLevel" /></xsl:when>
         <xsl:otherwise><xsl:value-of select="preceding-sibling::*/p/PlayerLevel[1]" /></xsl:otherwise>
      </xsl:choose>
   </xsl:template>

   <xsl:template match="/">
      <xsl:apply-templates select="root/data/element"/>
   </xsl:template>

   <xsl:template match="element">
      <xsl:text>This is </xsl:text><xsl:value-of select="e"/><xsl:text> event</xsl:text>
      <xsl:text>,</xsl:text>
      <xsl:call-template name="level"/>
      <xsl:text>,</xsl:text>
      <xsl:text>Some other data related to event </xsl:text><xsl:value-of select="e"/>
      <xsl:text>&#10;</xsl:text>
   </xsl:template>

   <xsl:template match="element[e='EndMission']">
      <xsl:text>This is the special EndMission event</xsl:text>
      <xsl:text>,</xsl:text>
      <xsl:call-template name="level"/>
      <xsl:text>,</xsl:text>
      <xsl:text>Some different data related to event EndMission</xsl:text>
      <xsl:text>&#10;</xsl:text>
   </xsl:template>
</xsl:stylesheet>

XSLT具有模板优先级的概念,具有为元素指定的条件的模板具有比仅与元素名称匹配的模板更高的优先级。

答案 1 :(得分:1)

您对该问题的描述自然会导致涉及兄弟递归的解决方案,其中每个项目都在处理上,同时考虑在处理前一项目时获得的信息。一般结构是这样的:

数据元素的模板规则处理其第一个子项:

<xsl:template match="data">
  <xsl:apply-templates select="element[1]">
    <xsl:with-param name="playerLevel" select="0"/>
  </xsl:apply-templates>
</xsl:template>

元素元素的模板规则处理该元素及其第一个后续兄弟,根据需要传递参数:

<xsl:template match="element">
  <xsl:param name="playerLevel" select="0"/>
  <!-- process this element -->
  ....
  <!-- process the next element -->
  <xsl:apply-templates select="following-sibling::element[1]">
   <xsl:with-param name="playerLevel" select="(p/playerLevel, $playerLevel)[1]"/>
  </xsl:apply-templates>
</xsl:template>

我在with-param中允许自己使用XSLT 2.0构造 - 如果存在则传递p/playerLevel,否则$playerLevel。如果您坚持使用XSLT 1.0,则必须将其扩展为更详细的xsl:choose指令。

这种方法非常强大,能够解决比你描述的更复杂的问题;但这是一项值得掌握的技术。需要注意的是,如果你有超过500个元素,它可能会在没有有效实现递归的处理器上崩溃。