2014-03-27 153 views
0

我有一个平面文件,我想使用XSLT转换为XML。 每行的第一个字符代表一块信息,我想将所有的东西组合在一起。 这些行可以以多个字符开头。我想要做的是在字符1之间组合一组线段。平面文件XML分组

这里是输入文件的样子:

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="'&#x0A;'" /> 
    <xsl:variable name="tab" select="'&#x09;'" /> 

     <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行开始一个新的汇总元素?

我为人人,通用的东西对不起,我有很多的数据一起工作,我试图简化问题。 如果需要更多信息,请告诉我。

回答

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和样式应该与it:main启动(模板撒克逊命名为main)),然后我得到的结果

<Root> 
    <Header> 
     <Period_start_date>xxxxxx</Period_start_date> 
    </Header> 
    <Summary id="xxxxxxxxxxx"> 
     <ID>xxxxxxxxxxx</ID> 
     <Batch_Date>xxxx</Batch_Date> 
     <data_from_2> 
     <Sales>xxx</Sales> 
     </data_from_2> 
     <data_from_3> 
     <Sales>xxx</Sales> 
     </data_from_3> 
     <data_from_5> 
     <Sales>xxx</Sales> 
     </data_from_5> 
     <data_from_8> 
     <Sales>xxx</Sales> 
     </data_from_8> 
    </Summary> 
    <Summary id="xxxxxxxxxxx"> 
     <ID>xxxxxxxxxxx</ID> 
     <Batch_Date>xxxx</Batch_Date> 
     <data_from_2> 
     <Sales>xxx</Sales> 
     </data_from_2> 
     <data_from_5> 
     <Sales>xxx</Sales> 
     </data_from_5> 
     <data_from_8> 
     <Sales>xxx</Sales> 
     </data_from_8> 
    </Summary> 
    <Summary id="xxxxxxxxxxx"> 
     <ID>xxxxxxxxxxx</ID> 
     <Batch_Date>xxxx</Batch_Date> 
     <data_from_8> 
     <Sales>xxx</Sales> 
     </data_from_8> 
    </Summary> 
    <Footer>xxxxxxxxxxxxxxxxxxxxxxxxx</Footer> 
</Root> 
+0

我知道你写的代码没有进行测试,但我得到的是说'多个项目的顺序是不允许的错误变量$ lines的值(<线/ >,<线/ > ...)'。我对XSL仍然很陌生,所以如果我完全不理解代码,我很抱歉。 – RXC

+0

对不起,该变量的类型声明缺少'*',我已经纠正了这一点。 –

+0

@RXC,我已经编辑与你应该能够更容易地适应您的需求比以前的建议,一个完整的代码示例答案。 –