XSL使用其包含元素的位置更新属性

时间:2017-12-31 22:17:19

标签: xml xslt xpath

我正在尝试更新看起来像这样的文档:

 <document n="foo">
   <body>
      <seg xml:id="xkj">some text</seg>
      <seg xml:id="njk">some text</seg>
      <seg xml:id="ine">some text</seg>
      <seg xml:id="ocu">some text</seg>
   </body>
 </document>

这样,每个seg/@xml:id都会使用文档中document/@nseg/()position的串联进行更新。

结果将是:

 <document n="foo">
   <body>
      <seg xml:id="foo-1">some text</seg>
      <seg xml:id="foo-2">some text</seg>
      <seg xml:id="foo-3">some text</seg>
      <seg xml:id="foo-4">some text</seg>
   </body>
 </document>

我尝试的代码是:

<xsl:variable name="var_val" select="tei:document/n@"/>

<xsl:template match="tei:seg/@xml:id">
        <xsl:value-of select="'$var_val' || '-' || parent::node()/position()"/>
</xsl:template>

但它结果如下,重复相同的position() = 1

 <document n="foo">
    <body>
      <seg xml:id="foo-1">some text</seg>
      <seg xml:id="foo-1">some text</seg>
      <seg xml:id="foo-1">some text</seg>
      <seg xml:id="foo-1">some text</seg>
    </body>
 </document>

我要么不理解position(),要么不正确地遍历XPATH轴。

提前致谢。

3 个答案:

答案 0 :(得分:2)

在匹配属性的模板环境中,

position()不是正确的工具,您需要count(../(., preceding-sibling::seg))或者您可以使用xsl:number

  <xsl:template match="seg/@xml:id">
      <xsl:variable name="pos" as="xs:integer">
          <xsl:number count="seg"/>
      </xsl:variable>
      <xsl:attribute name="{name()}" namespace="{namespace-uri()}" select="$var_val, $pos" separator="-"/>
  </xsl:template>

http://xsltfiddle.liberty-development.net/pPgCcok

答案 1 :(得分:1)

position()仅适用于节点集。用表达式

<xsl:template match="tei:seg/@xml:id">

您要在此模板的每次匹配时将position()重置为一个。

因此,最好使用<xsl:for-each...>来预期增加数量:

<xsl:variable name="var_val" select="/tei:document/@n"/>

<xsl:template match="tei:body">
  <xsl:for-each select="tei:seg">
    <seg xml:id="{concat($var_val, '-', position())}">
      <xsl:copy-of select="node()" />
    </seg>
  </xsl:for-each>
</xsl:template>

它的输出是:

<seg xml:id="foo-1">some text</seg>
<seg xml:id="foo-2">some text</seg>
<seg xml:id="foo-3">some text</seg>
<seg xml:id="foo-4">some text</seg>

答案 2 :(得分:0)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tei="http://tei">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:variable name="var_val" select="/tei:document/@n"/>
<xsl:template match="tei:document">
  <xsl:copy><xsl:copy-of select="@n"/><xsl:apply-templates/></xsl:copy>
</xsl:template>
<xsl:template match="tei:body">
  <xsl:copy><xsl:apply-templates/></xsl:copy>
</xsl:template>
<xsl:template match="tei:seg">
<xsl:copy><xsl:attribute name="xml:id"><xsl:value-of select="concat(concat($var_val,'-'),position())"/></xsl:attribute><xsl:value-of select="text()"/></xsl:copy>
</xsl:template>
</xsl:stylesheet>

上面的代码将生成所需的输出,提供从输入中删除的空格:

<?xml version="1.0" encoding="UTF-8"?><document n="foo" xmlns="http://tei"><body><seg xml:id="xkj">some text</seg><seg xml:id="njk">some text</seg><seg xml:id="ine">some text</seg><seg xml:id="ocu">some text</seg></body></document>