在tokenize结果循环上使用previous-sibling时遇到问题

时间:2014-08-20 14:00:16

标签: xslt

我试图使用XSLT将平面文本文件解析为XML。单个"记录"我生成的XML文件可能包含我的文本文件的多行:

12345 Bob 100.00
12345 Bob 50.00
34567 Joe 20.00

我想要做的只是标识符一次,然后为文本文件的每一行创建唯一的金额元素:

<record>
  <person>
    <name>Bob</name>
    <id>12345</id>
  </person>
  <amounts>
    <amount>100.00</amount>
    <amount>50.00</amount>
  </amounts>
</record>
<record>
  <person>
    <name>Joe</name>
    <id>34567</id>
  </person>
  <amounts>
    <amount>20.00</amount>
  </amounts>
</record>

通常我将我的输入文件和标记化在换行符上,循环并写出每条记录

<xsl:variable name="src" select="unparsed-text($inputfile,'UTF-8')" />
<xsl:for-each select="tokenize($src, '&#10;')" >

我希望我能做到这一点。将$previousId变量与当前行的已解析ID进行比较,如果它们不同则写入person信息,否则只需编写amount条记录。最后使用当前ID更新$previousId。但是XSLT变量无法更新。

之后我想也许我可以使用类似select="preceding-sibling::.[1]"的东西,但是抱怨因为tokenize显然不是返回节点,而是一种xs:string

那么有没有办法可以迭代一个标记化字符串的结果,但不知何故与前一行进行比较?

2 个答案:

答案 0 :(得分:1)

此处preceding-sibling轴的问题在于,标记化序列中的项目 - 只是一个序列,它们既不是彼此的兄弟,也不是它们的明显。

  

那么有没有办法可以迭代标记化的结果   字符串,但不知何故与上一行比较?

是的,有办法做到这一点。注意:您没有显示太多的XSLT代码,所以我必须在某种程度上假设它。


但是你可以使变量成为一系列标记化字符串:

<xsl:variable name="src" select="tokenize(unparsed-text($inputfile,'UTF-8'),'&#10;')" />

然后,您可以通过索引引用变量中的项目,例如$src[1]为您提供第一行。

此外,如果在for-each循环内,您可以参考前一行

<xsl:for-each select="$src">
  <xsl:if test="string-length(.) le string-length($src[position() -1])">
    <!--More code-->
  </xsl:if>
</xsl:for-each>

上方,.是当前行,$src[position() -1])是紧接其前一行。

答案 1 :(得分:1)

这是另一种看待它的方式:

XSLT 2.0

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

<xsl:param name="inputfile"/>
<xsl:key name="record" match="record" use="field[1]" />

<xsl:template match="/">
    <!-- first pass -->
    <xsl:variable name="records">
        <xsl:for-each select="tokenize(unparsed-text($inputfile,'UTF-8'), '&#10;')" >
            <record>
                <xsl:for-each select="tokenize(., ' ')" >
                    <field>
                        <xsl:value-of select="." />
                    </field>
                </xsl:for-each>
            </record>
        </xsl:for-each>
    </xsl:variable> 
    <!-- output -->
    <output>
        <xsl:for-each select="distinct-values($records/record/field[1])" >
            <record>
                <id><xsl:value-of select="." /></id>
                <name><xsl:value-of select="key('record', ., $records)[1]/field[2]" /></name>
                <amounts>
                    <xsl:for-each select="key('record', ., $records)" >
                        <amount><xsl:value-of select="field[3]" /></amount>
                    </xsl:for-each>
                </amounts>
            </record>
        </xsl:for-each>
    </output>
</xsl:template>

</xsl:stylesheet>