我有一个平面文件,我想使用XSLT转换为XML。
每行的第一个字符代表一个信息块,我想将所有内容组合在一起。
这些行可以以多个字符开头。我想要做的是将字符块组合在一起,它们位于字符1
之间。
这是输入文件的样子:
0xxxxxxxxxxxxxxxxxxxxxxxxx
1xxxxxxxxxxxxxxxxxxxxxxxxx
2xxxxxxxxxxxxxxxxxxxxxxxxx
3xxxxxxxxxxxxxxxxxxxxxxxxx
5xxxxxxxxxxxxxxxxxxxxxxxxx
8xxxxxxxxxxxxxxxxxxxxxxxxx
1xxxxxxxxxxxxxxxxxxxxxxxxx
2xxxxxxxxxxxxxxxxxxxxxxxxx
5xxxxxxxxxxxxxxxxxxxxxxxxx
8xxxxxxxxxxxxxxxxxxxxxxxxx
1xxxxxxxxxxxxxxxxxxxxxxxxx
8xxxxxxxxxxxxxxxxxxxxxxxxx
9xxxxxxxxxxxxxxxxxxxxxxxxx
x
只表示我可以处理的行中的数据。
我想要做的就是产品:
<Root>
<Header> // O line
</Header>
<Summary id="xxxxx"> // First 1 line
<data_from_2>
</data_from_2>
<data_from_3>
</data_from_3>
<data_from_5>
</data_from_5>
<data_from_8>
</data_from_8>
</Summary>
<Summary id="xxxxx"> // Second 1 line
<data_from_2>
</data_from_2>
<data_from_3>
</data_from_3>
<data_from_5>
</data_from_5>
<data_from_8>
</data_from_8>
</Summary>
<Summary id="xxxxx"> // Third 1 line
<data_from_2>
</data_from_2>
<data_from_3>
</data_from_3>
<data_from_5>
</data_from_5>
<data_from_8>
</data_from_8>
</Summary>
<Footer> // 9 line
</Footer>
</Root>
困难的部分是不知道1
行下会有多少行。
可能只有一行可以分组或更多行。
这是我最初的XSLT(它目前产生一个扁平结构):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="newline" select="'
'" />
<xsl:variable name="tab" select="'	'" />
<xsl:template match="/">
<xsl:value-of select="$newline"/>
<FirstData>
<xsl:value-of select="$newline"/>
<xsl:for-each select="tokenize(.,'\r?\n')">
<!-- DETERMINE WHAT FIRST CHAR LOOKS LIKE -->
<xsl:variable name="lineToken" select="substring(., 1, 1)"/>
<!-- HEADER -->
<xsl:if test="$lineToken='0'">
<xsl:variable name="periodStart" select="substring(., 2, 6)"/>
<xsl:value-of select="$tab"/><HEADER><xsl:value-of select="$newline"/>
<xsl:value-of select="$tab"/><xsl:value-of select="$tab"/><Period_start_date><xsl:sequence select="$periodStart"/></Period_start_date><xsl:value-of select="$newline"/>
<xsl:value-of select="$tab"/></HEADER><xsl:value-of select="$newline"/>
</xsl:if>
<!-- SUMMARY -->
<xsl:if test="$lineToken='1'">
<xsl:value-of select="$tab"/><xsl:element name="SUMMARY">
<xsl:attribute name="ID"><xsl:value-of select ="substring(., 2, 11)"/></xsl:attribute>
<xsl:value-of select="$newline"/>
<xsl:variable name="ID" select="substring(., 2, 11)"/>
<xsl:variable name="batchDate" select="substring(., 13, 4)"/>
<xsl:value-of select="$tab"/><xsl:value-of select="$tab"/><ID><xsl:sequence select="$fdmsMerchantNum"/></FDMS_Merchant_Number><xsl:value-of select="$newline"/>
<xsl:value-of select="$tab"/><xsl:value-of select="$tab"/><Batch_Date><xsl:sequence select="$batchDate"/></Batch_Date><xsl:value-of select="$newline"/>
<xsl:value-of select="$tab"/></xsl:element><xsl:value-of select="$newline"/>
</xsl:if>
<!-- Data 2 -->
<xsl:if test="$lineToken='2'">
<xsl:value-of select="$tab"/><Data_2><xsl:value-of select="$newline"/>
<xsl:variable name="Sales" select="substring(., 2, 3)"/>
<xsl:value-of select="$tab"/><xsl:value-of select="$tab"/><Sales><xsl:sequence select="$Sales"/></Sales><xsl:value-of select="$newline"/>
<xsl:value-of select="$tab"/></Data_2><xsl:value-of select="$newline"/>
</xsl:if>
<!-- Data 3 -->
<xsl:if test="$lineToken='3'">
<xsl:value-of select="$tab"/><Data_3><xsl:value-of select="$newline"/>
<xsl:variable name="Sales" select="substring(., 2, 3)"/>
<xsl:value-of select="$tab"/><xsl:value-of select="$tab"/><Sales><xsl:sequence select="$Sales"/></Sales><xsl:value-of select="$newline"/>
<xsl:value-of select="$tab"/></Data_3><xsl:value-of select="$newline"/>
</xsl:if>
<!-- Data 5 and Data 8 elements are identical -->
</xsl:for-each>
</Root>
</xsl:template>
</xsl:stylesheet>
我想要做的是能够将数据2和数据3元素嵌套在摘要元素中,但是如何处理这些行然后为下一个遇到的1行开始一个新的摘要元素?
我很抱歉所有的通用内容,我有很多数据可以使用,我正在尝试简化问题。 如果需要更多信息,请告诉我。
答案 0 :(得分:1)
它看起来像for-each-group group-starting-with
的作业,但在XSLT 2.0中,您只能将其用于节点序列,而不能用于字符串序列。所以我首先将你从tokenize(.,'\r?\n')
获得的行包装成一个元素,例如
<xsl:variable name="lines" as="element(line)*">
<xsl:for-each select="tokenize(.,'\r?\n')">
<line><xsl:value-of select="."/></line>
</xsl:for-each>
</xsl:variable>
然后我会用
<xsl:for-each-group select="$lines" group-starting-with="line[starts-with(., '1')]">
<xsl:choose>
<xsl:when test="not(self::line[starts-with(., '1')])">
<!-- header -->
<Header><xsl:value-of select="substring(., 2)"/></Header>
</xsl:when>
<xsl:otherwise>
<Summary id="{substring(., 2)}">
<!-- now use for-each select="if (position() eq last()) then current-group()[position() gt 1 and position() ne last()] else current-group()[position() gt 1]" or apply-templates to output the lines-->
<xsl:for-each select="if (position() eq last()) then current-group()[position() gt 1 and position() ne last()] else current-group()[position() gt 1]">
<xsl:element name="data_from_{substring(., 1, 1)}"><xsl:value-of select="substring(., 2)"/></xsl:element>
</xsl:for-each>
</Summary>
<xsl:if test="position() eq last()">
<Footer>
<xsl:value-of select="substring(current-group()[last()], 2)"/>
</Footer>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
分组。
我现在已经找到了一些时间来编写一个工作样本,XSLT是
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:param name="text-url" select="'test2014032901.txt'"/>
<xsl:output indent="yes"/>
<xsl:template name="main">
<xsl:variable name="text" select="unparsed-text($text-url)"/>
<xsl:variable name="lines" as="element(line)*">
<xsl:for-each select="tokenize($text,'\r?\n')[normalize-space()]">
<line><xsl:value-of select="."/></line>
</xsl:for-each>
</xsl:variable>
<Root>
<xsl:for-each-group select="$lines" group-starting-with="line[starts-with(., '1')]">
<xsl:choose>
<xsl:when test="not(self::line[starts-with(., '1')])">
<!-- header -->
<xsl:variable name="periodStart" select="substring(., 2, 6)"/>
<Header>
<Period_start_date>
<xsl:value-of select="$periodStart"/>
</Period_start_date>
</Header>
</xsl:when>
<xsl:otherwise>
<Summary id="{substring(., 2, 11)}">
<ID><xsl:value-of select="substring(., 2, 11)"/></ID>
<Batch_Date><xsl:value-of select="substring(., 13, 4)"/></Batch_Date>
<!-- now use for-each select="if (position() eq last()) then current-group()[position() gt 1 and position() ne last()] else current-group()[position() gt 1]" or apply-templates to output the lines-->
<xsl:for-each select="if (position() eq last()) then current-group()[position() gt 1 and position() ne last()] else current-group()[position() gt 1]">
<xsl:element name="data_from_{substring(., 1, 1)}">
<Sales>
<xsl:value-of select="substring(., 2, 3)"/>
</Sales>
</xsl:element>
</xsl:for-each>
</Summary>
<xsl:if test="position() eq last()">
<Footer>
<xsl:value-of select="substring(current-group()[last()], 2)"/>
</Footer>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</Root>
</xsl:template>
</xsl:stylesheet>
纯文本文件的名称作为参数text-url
传入,样式表应该以{{1}}(Saxon的名为it:main
的模板)开始,然后我得到结果
main