xslt中的值增量

时间:2012-07-26 15:32:16

标签: xml xslt xpath

我需要根据属性增加xslt中的值。假设我的xml像这样,

   <comp>
   <fig xml:id="c1-fig-001"/>
   <fig xml:id="c1-fig-002"/>
   <fig xml:id="c1-fig-003"/>
   <fig xml:id="c1-fig-004" resumeatnum="7"/>
   <fig xml:id="c1-fig-005"/>
   <fig xml:id="c1-fig-006"/>
   <fig xml:id="c1-fig-007" resumeatnum="18"/>
   <fig xml:id="c1-fig-008"/>
   <fig xml:id="c1-fig-009"/>
   </comp>

我需要像这样的输出,

<comp>
<fig xml:id="c1-fig-001"/>
<fignum>1.1</fignum>
<fig xml:id="c1-fig-002"/>
<fignum>1.2</fignum>
<fig xml:id="c1-fig-003"/>
<fignum>1.3</fignum>
<fig xml:id="c1-fig-004" resumeatnum="7"/>
<fignum>1.7</fignum>
<fig xml:id="c1-fig-005"/>
<fignum>1.8</fignum>
<fig xml:id="c1-fig-006"/>
<fignum>1.9</fignum>
<fig xml:id="c1-fig-007" resumeatnum="18"/>
<fignum>1.18</fignum>
<fig xml:id="c1-fig-008"/>
<fignum>1.19</fignum>
<fig xml:id="c1-fig-009"/>
<fignum>1.20</fignum>
</comp>

我需要从xml:id中获取1属性的值,以及c1之后的数字中的另一个数字。

如果有属性fig,那么我需要使用该值而不是正常值,并增加以下节点的值。请提供xslt来执行此操作。

5 个答案:

答案 0 :(得分:1)

以下XSLT 2.0样式表:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  exclude-result-prefixes="xs" 
  version="2.0">

  <xsl:template match="comp">
    <xsl:for-each-group select="fig" group-starting-with="*[@resumeatnum]">
      <xsl:variable name="base" select="(@resumeatnum, 1)[1] - 1"/>
      <xsl:for-each select="current-group()">
        <xsl:copy-of select="."/>
        <fignum>1.<xsl:value-of select="position()+$base"/></fignum>
      </xsl:for-each>
    </xsl:for-each-group>
  </xsl:template>

</xsl:stylesheet>

产生以下输出:

<?xml version="1.0" encoding="UTF-8"?>
<fig xml:id="c1-fig-001"/>
<fignum>1.1</fignum>
<fig xml:id="c1-fig-002"/>
<fignum>1.2</fignum>
<fig xml:id="c1-fig-003"/>
<fignum>1.3</fignum>
<fig xml:id="c1-fig-004" resumeatnum="7"/>
<fignum>1.7</fignum>
<fig xml:id="c1-fig-005"/>
<fignum>1.8</fignum>
<fig xml:id="c1-fig-006"/>
<fignum>1.9</fignum>
<fig xml:id="c1-fig-007" resumeatnum="18"/>
<fignum>1.18</fignum>
<fig xml:id="c1-fig-008"/>
<fignum>1.19</fignum>
<fig xml:id="c1-fig-009"/>
<fignum>1.20</fignum>

答案 1 :(得分:1)

这是一个较短的(33个格式良好的短线)和更简单的XSLT 1.0解决方案(三个短模板,没有substring(),没有substring-before(),没有复杂和长的多线表达式,没有concat(),没有xsl:for-each,没有xsl:if,没有xsl:variable,没有string-length(),没有xsl:call-template

<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:key name="kFollowing" match="fig[not(@resumeatnum)]"
      use="generate-id((preceding-sibling::*[@resumeatnum][1]
                      |
                        ..
                        )[last()]
                      )"/>

 <xsl:template match="/*">
  <comp>
   <xsl:apply-templates select="key('kFollowing', generate-id())"/>
   <xsl:apply-templates select="fig[@resumeatnum]"/>
  </comp>
 </xsl:template>

 <xsl:template match="fig">
  <xsl:param name="pStart" select="1"/>

  <fig xml:id="{@xml:id}"/>
   <fignum>1.<xsl:value-of select="position() + $pStart -1"/></fignum>
 </xsl:template>

 <xsl:template match="fig[@resumeatnum]">
   <fig xml:id="{@xml:id}" resumeatnum="{@resumeatnum}"/>
   <fignum>1.<xsl:value-of select="@resumeatnum"/></fignum>
  <xsl:apply-templates select="key('kFollowing', generate-id())">
   <xsl:with-param name="pStart" select="@resumeatnum+1"/>
  </xsl:apply-templates>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档时:

<comp>
    <fig xml:id="c1-fig-001"/>
    <fig xml:id="c1-fig-002"/>
    <fig xml:id="c1-fig-003"/>
    <fig xml:id="c1-fig-004" resumeatnum="7"/>
    <fig xml:id="c1-fig-005"/>
    <fig xml:id="c1-fig-006"/>
    <fig xml:id="c1-fig-007" resumeatnum="18"/>
    <fig xml:id="c1-fig-008"/>
    <fig xml:id="c1-fig-009"/>
</comp>

产生了想要的正确结果

<comp>
   <fig xml:id="c1-fig-001"/>
   <fignum>1.1</fignum>
   <fig xml:id="c1-fig-002"/>
   <fignum>1.2</fignum>
   <fig xml:id="c1-fig-003"/>
   <fignum>1.3</fignum>
   <fig xml:id="c1-fig-004" resumeatnum="7"/>
   <fignum>1.7</fignum>
   <fig xml:id="c1-fig-005"/>
   <fignum>1.8</fignum>
   <fig xml:id="c1-fig-006"/>
   <fignum>1.9</fignum>
   <fig xml:id="c1-fig-007" resumeatnum="18"/>
   <fignum>1.18</fignum>
   <fig xml:id="c1-fig-008"/>
   <fignum>1.19</fignum>
   <fig xml:id="c1-fig-009"/>
   <fignum>1.20</fignum>
</comp>

答案 2 :(得分:0)

这样的事情可能会起作用

<xsl:for-each select="/comp/fig">
    <fignum>1.<xsl:value-of select="substring(@xml:id,string-length(@xml:id),1)"/>1</fignum>
</xsl:for-each>

暂时没有使用xslt / xpath所以可能不完美。基本上只是循环通过无花果节点和子串最后一个字符。如果要循环使用超过9个节点,则必须更改子字符串以获取所有数字

答案 3 :(得分:0)

PigChicken,我认为他要求根据之前的[if existing] resumeatnum属性修改自动增量功能。通过为主要和次要版本组件创建变量,然后将简历中的“偏移量”添加到相应的次要版本,以下内容适用于给定示例。例如,resumeatnum为18,次要版本为7,偏移量为11,也会添加到以下次要版本中。我使用了number()强制转换,并且可能会删除其中的一些。这是变换:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.1" exclude-result-prefixes="" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>
    <xsl:template match="/comp">
        <comp>
            <xsl:for-each select="./fig">
                <xsl:copy-of select="."/>
                <xsl:variable name="major">
                    <xsl:value-of select="substring-after(substring-before(./@xml:id,'-'),'c')"/>
                </xsl:variable>
                <xsl:variable name="minor">
                    <xsl:value-of select="number(substring-after(./@xml:id,'fig-'))"/>
                </xsl:variable>
                <xsl:variable name="resume_offset">
                    <xsl:if test="./@resumeatnum">
                        <xsl:value-of select="number(./@resumeatnum - $minor)"/>
                    </xsl:if>
                    <xsl:if test="not(./@resumeatnum)">
                        <xsl:if test="./preceding-sibling::*[@resumeatnum]">
                            <xsl:value-of select="number(./preceding-sibling::*[@resumeatnum][1]/@resumeatnum) - number(substring-after(./preceding-sibling::*[@resumeatnum][1]/@xml:id,'fig-'))"/>
                        </xsl:if>
                        <xsl:if test="not(./preceding-sibling::*[@resumeatnum])">
                            <xsl:value-of select="number(0)"/>
                        </xsl:if>
                    </xsl:if>
                </xsl:variable>
                <fignum>
                    <xsl:value-of select="$major"/>
                    <xsl:text>.</xsl:text>
                    <xsl:value-of select="$minor+$resume_offset"/>
                </fignum>
            </xsl:for-each>
        </comp>
    </xsl:template>
</xsl:stylesheet>

答案 4 :(得分:0)

另一种方法是首先匹配第一个 fig 元素

<xsl:apply-templates select="fig[1]"/>

然后你有一个主模板来匹配 fig 元素,但是有一个参数可以保存'递增'值。请注意,它也充当命名模板。

<xsl:template match="fig" name="fig">
   <xsl:param name="sequence" select="1"/>

在此范围内,您可以输出 fignum 元素

<fignum>
   <xsl:value-of 
      select="concat(substring-before(substring(@xml:id, 2, string-length(@xml:id) - 1), '-'), '.', $sequence)"/>
</fignum>

然后你会匹配下一个 fig 元素,增加参数的值

  <xsl:apply-templates select="following-sibling::fig[1]">
     <xsl:with-param name="sequence" select="$sequence + 1"/>
  </xsl:apply-templates>

要重置序列,您只需要一个匹配 fig 元素的模板,这些元素具有相关属性,您只需使用属性值调用命名模板即可覆盖它

<xsl:template match="fig[@resumeatnum != '']">
   <xsl:call-template name="fig">
      <xsl:with-param name="sequence" select="@resumeatnum"/>
   </xsl:call-template>
</xsl:template>

这是完整的XSLT

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

   <xsl:template match="comp">
      <comp>
         <xsl:apply-templates select="fig[1]"/>
      </comp>
   </xsl:template>

   <xsl:template match="fig[@resumeatnum != '']">
      <xsl:call-template name="fig">
         <xsl:with-param name="sequence" select="@resumeatnum"/>
      </xsl:call-template>
   </xsl:template>

   <xsl:template match="fig" name="fig">
      <xsl:param name="sequence" select="1"/>
      <fig>
         <xsl:apply-templates select="@*"/>
         <fignum>
            <xsl:value-of select="concat(substring-before(substring(@xml:id, 2, string-length(@xml:id) - 1), '-'), '.', $sequence)"/>
         </fignum>
      </fig>
      <xsl:apply-templates select="following-sibling::fig[1]">
         <xsl:with-param name="sequence" select="$sequence + 1"/>
      </xsl:apply-templates>
   </xsl:template>

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

当应用于您的示例XML时,输出以下内容

<comp>
   <fig xml:id="c1-fig-001">
      <fignum>1.1</fignum>
   </fig>
   <fig xml:id="c1-fig-002">
      <fignum>1.2</fignum>
   </fig>
   <fig xml:id="c1-fig-003">
      <fignum>1.3</fignum>
   </fig>
   <fig xml:id="c1-fig-004" resumeatnum="7">
      <fignum>1.7</fignum>
   </fig>
   <fig xml:id="c1-fig-005">
      <fignum>1.8</fignum>
   </fig>
   <fig xml:id="c1-fig-006">
      <fignum>1.9</fignum>
   </fig>
   <fig xml:id="c1-fig-007" resumeatnum="18">
      <fignum>1.18</fignum>
   </fig>
   <fig xml:id="c1-fig-008">
      <fignum>1.19</fignum>
   </fig>
   <fig xml:id="c1-fig-009">
      <fignum>1.20</fignum>
   </fig>
</comp>