我试图使用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, ' ')" >
我希望我能做到这一点。将$previousId
变量与当前行的已解析ID进行比较,如果它们不同则写入person
信息,否则只需编写amount
条记录。最后使用当前ID更新$previousId
。但是XSLT变量无法更新。
之后我想也许我可以使用类似select="preceding-sibling::.[1]"
的东西,但是抱怨因为tokenize显然不是返回节点,而是一种xs:string
。
那么有没有办法可以迭代一个标记化字符串的结果,但不知何故与前一行进行比较?
答案 0 :(得分:1)
此处preceding-sibling
轴的问题在于,标记化序列中的项目 - 只是一个序列,它们既不是彼此的兄弟,也不是它们的明显。
那么有没有办法可以迭代标记化的结果 字符串,但不知何故与上一行比较?
是的,有办法做到这一点。注意:您没有显示太多的XSLT代码,所以我必须在某种程度上假设它。
但是你可以使变量成为一系列标记化字符串:
<xsl:variable name="src" select="tokenize(unparsed-text($inputfile,'UTF-8'),' ')" />
然后,您可以通过索引引用变量中的项目,例如$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'), ' ')" >
<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>