XSLT 1.0:从外部文档

时间:2015-04-23 12:14:51

标签: xml xslt xslt-1.0

我正在尝试使用xslt来执行xml到xml的转换,这样每个元素都会被赋予一个GUID,从外部xml文档按顺序提取。

来源xml:

<?xml version="1.0"?>
<dataSets>
  <data name="foo"/>
  <data name="bar"/>
  ...
</dataSets>

ID列表:

<?xml version="1.0"?>
<ids>
  <id>some-GUID</id>
  <id>another-GUID</id>
  ...
</ids>

期望的输出:

<?xml version="1.0"?>
<dataSets>
  <data name="foo" id="some-GUID"/>
  <data name="bar" id="another-GUID"/>
  ...
</dataSets>

但我每次都得到同样的第一张身份证明:

<?xml version="1.0"?>
<dataSets>
  <data name="foo" id="some-GUID"/>
  <data name="bar" id="some-GUID"/>
  ...
</dataSets>

到目前为止,这是我得到的xsl:

<?xml version="1.0"?>
<xsl:transform version="1.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>

  <xsl:template match="dataSets">
    <xsl:for-each select="data">
      <xsl:variable name="c">
        <xsl:number value="count(preceding-sibling::*|self::*)"/>
      </xsl:variable>

      <xsl:copy>
        <xsl:attribute name="id">
          <xsl:value-of select="document('idList.xml')/ids/id[$c]"/>
        </xsl:attribute>
        <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>

    </xsl:for-each>
  </xsl:template>

</xsl:transform>

我尝试将<xsl:attribute name="num"><xsl:value-of select="$c"/></xsl:attribute>添加到xsl,以查看每次迭代时变量是什么,它从1开始,每次都通过for-each递增,正如我所做的那样。我希望如此,我不知道它为什么不起作用 任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:1)

怎么样:

XSLT 1.0

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

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

<xsl:template match="data">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:variable name="i" select="count(preceding::data) + 1" />
        <xsl:attribute name="id">
            <xsl:value-of select="document('idList.xml')/ids/id[$i]"/>
        </xsl:attribute>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

注意

  1. 如果所有data个元素都是同一个dataSets父级下的兄弟姐妹,则可以通过仅计算前面的兄弟姐妹来加快这一点:

    <xsl:variable name="i" select="count(preceding-sibling::data) + 1" />
    
  2. 可能有更好的方法将GUID分配给节点。

  3. 附加说明:

    您尝试不起作用的原因是两个因素的组合:

    首先,您定义变量的方式:

    <xsl:variable name="c">
       <xsl:number value="count(preceding-sibling::*|self::*)"/>
    </xsl:variable>
    

    导致变量为结果树片段。该变量包含单个根节点,xsl:number生成的字符串是该节点的子节点。

    接下来,您尝试在表达式中将变量用作数字谓词

    <xsl:value-of select="document('idList.xml')/ids/id[$c]"/>
    

    但是,由于变量不是一个数字,它被评估为布尔值 - 并且非空为它返回true,导致 all id传递测试的节点(当然,在XSLT 1.0 xsl:value中只会返回第一个的值)。

    如何修复:

    有三种方法可以解决此问题:

    1. 不要将变量用作数字谓词。相反,将它放在一个表达式中,将其与显式位置进行比较(如@potame在答案中所建议的那样):

      <xsl:value-of select="document('idList.xml')/ids/id[position()=$c]"/>
      
    2. 在将其用作谓词之前将其转换为数字:

      <xsl:value-of select="document('idList.xml')/ids/id[number($c)]"/>
      
    3. 通过使用select属性定义变量,从一开始就消除问题,这将导致变量成为开头的数字:

      <xsl:variable name="c" select="count(preceding-sibling::*|self::*)" />
      
    4. 另见:
      http://www.w3.org/TR/xslt/#variable-values
      http://www.w3.org/TR/xpath/#predicates

答案 1 :(得分:0)

您只需要通过position()使用 <xsl:value-of select="document('idList.xml')/ids/id[position() = $c]"/> 轻松更改指令以检索所需索引处的元素:

<xsl:template match="dataSets">
    <xsl:variable name="idList" select="document('idList.xml')/ids"/>

    <xsl:for-each select="data">
        <xsl:variable name="c">
            <xsl:number value="count(preceding-sibling::*|self::*)"/>
        </xsl:variable>

        <xsl:copy>
            <xsl:attribute name="id">
                <xsl:value-of select="$idList/id[position() = $c]"/>
            </xsl:attribute>

            <xsl:apply-templates select="node()|@*"/>
            <xsl:value-of select="$c" />
        </xsl:copy>

    </xsl:for-each>
</xsl:template>

我建议您使用变量来避免多次解析文档:

java.util.Date