我需要使用xslt从文本文件生成格式良好的XML结构。我是xslt转换的新手,对我来说这看起来有点挑战。 示例文本文件如下。我需要省略第一部分并将引号中的值映射到输出xml文件。
Directory: sample/archive
Name: 20130613-T210002.TXT
---------------------------------------------------------------
"11FCK1GR0026" "G190" "FPB - OK Ship Pt" "A" "11" "XX" "02"
"11FCA1GR0034" "G980" "FPB -San Antonio" "A" "11" "XX" "02"
"11FCA1GR0034" "G160" "FPB -San Antonio" "A" "11" "XX" "02"
以下是所需的输出xml格式:
<Account>
<Action>A</Action> <!-- 3rd element in the row-->
<org>G190</org> <!-- 2nd element-->
<code>11FCK1GR002611XX</code> <!--concat(1st element, 4th element, 5th element)-->
<FiscalYear>2013</FiscalYear> <!--calculate fiscal year from current date -->
<Info>
<Action>A</Action> <!-- 3rd element in the row-->
<org>G190</org> <!-- 2nd element-->
<code>11FCK1GR002611XX</code><!--concat(1st element, 4th element, 5th element)-->
<Fieldlab>Acc1</Fieldlab> <!-- Static value-->
<FieldVal>11FCK1GR0026 </FieldVal> <!-- if field order is 1, map 1st element -->
<FieldOrd>1</FieldOrd> <!-- Static value-->
<Info>
<Info>
<Action>A</Action>
<org>G190</org>
<code>11FCK1GR002611XX</code>
<Fieldlab>Acc2</Fieldlab>
<FieldVal>11</FieldVal> <!-- if field order is 2, map 5th element -->
<FieldOrd>2</FieldOrd>
<Info>
<Info>
<Action>A</Action> <!-- 4th element in the row-->
<org>G190</org> <!-- 2nd element-->
<code>11FCK1GR002611XX</code>
<Fieldlab>Acc3</Fieldlab>
<FieldVal>xx</FieldVal> <!-- if field order is 3, map 6th element -->
<FieldOrd>3</FieldOrd>
<Info>
<Info>
<Action>A</Action> <!-- 4th element in the row-->
<org>G190</org> <!-- 2nd element-->
<code>11FCK1GR002611XX</code>
<Fieldlab>Acc4</Fieldlab>
<FieldVal>02</FieldVal> <!-- if field order is 4, map 7th element -->
<FieldOrd>4</FieldOrd>
<Info>
<Info>
<Action>A</Action> <!-- 4th element in the row-->
<org>G190</org> <!-- 2nd element-->
<code>11FCK1GR002611XX</code>
<Fieldlab>Acc5</Fieldlab>
<FieldVal>FPB - OK Ship Pt</FieldVal> <!-- if field order is 5, map 3rd element -->
<FieldOrd>5</FieldOrd>
<Info>
</Account>
<Account>
<Action>A</Action> <!-- 3rd element in the row-->
<org>G980</org> <!-- 2nd element-->
<code>111FCA1GR003411XX</code> <!--concat(1st element, 4th element, 5th element)-->
<FiscalYear>2013</FiscalYear>
<Info>
<Action>A</Action> <!-- 3rd element in the row-->
<org>G190</org> <!-- 2nd element-->
<code>111FCA1GR003411XX</code><!--concat(1st element, 4th element, 5th element)-->
<Fieldlab>Acc1</Fieldlab>
<FieldVal>11FCA1GR0034</FieldVal> <!-- if field order is 1, map 1st element -->
<FieldOrd>1</FieldOrd>
<Info>
<Info>
<Action>A</Action>
<org>G190</org>
<code>111FCA1GR003411XX</code>
<Fieldlab>Acc2</Fieldlab>
<FieldVal>11</FieldVal> <!-- if field order is 2, map 5th element -->
<FieldOrd>2</FieldOrd>
<Info>
<Info>
<Action>A</Action> <!-- 4th element in the row-->
<org>G190</org> <!-- 2nd element-->
<code>111FCA1GR003411XX</code>
<Fieldlab>Acc3</Fieldlab>
<FieldVal>xx</FieldVal> <!-- if field order is 3, map 6th element -->
<FieldOrd>3</FieldOrd>
<Info>
<Info>
<Action>A</Action> <!-- 4th element in the row-->
<org>G190</org> <!-- 2nd element-->
<code>111FCA1GR003411XX</code>
<Fieldlab>Acc4</Fieldlab>
<FieldVal>02</FieldVal> <!-- if field order is 4, map 7th element -->
<FieldOrd>4</FieldOrd>
<Info>
<Info>
<Action>A</Action> <!-- 4th element in the row-->
<org>G190</org> <!-- 2nd element-->
<code>111FCA1GR003411XX</code>
<Fieldlab>Acc5</Fieldlab>
<FieldVal>FPB -San Antonio</FieldVal> <!-- if field order is 5, map 3rd element -->
<FieldOrd>5</FieldOrd>
<Info>
</Account>
有人可以帮我生成这个文件吗?提前谢谢!
答案 0 :(得分:2)
我会分两个阶段进行这种转换(通过分解来简化任务)。第一阶段产生与原始文本同构的XML;第二阶段重构XML。
阶段1是这样的:
<xsl:template name="main">
<doc>
<xsl:for-each select="tokenize(unparsed-text('input.txt'), '\r?\n')
[starts-with(., '"')]">
<row>
<xsl:analyze-string select="." regex='\"[^"]*?\"'>
<xsl:matching-substring>
<col><xsl:value-of select="."/></col>
</xsl:matching-substring>
</xsl:analyze-string>
</row>
</xsl:for-each>
</doc>
</xsl:template>
阶段2是这样的:
<xsl:template match="doc">
<Accounts>
<xsl:apply-templates/>
</Accounts>
</xsl:template>
<xsl:template match="row">
<xsl:variable name="row" select="."/>
<Account>
<Action><xsl:value-of select="col[4]"/></Action>
<org><xsl:value-of select="col[2]"/></org>
<xsl:variable name="code" select="concat(col[1], col[4], col[5])"/>
<code><xsl:value-of select="$code"/></code>
<FiscalYear><xsl:value-of select="year-from-date(current-date())"/></FiscalYear>
<xsl:for-each select="1 to 5">
<xsl:variable name="p" select="."/>
<Info>
<Action><xsl:value-of select="$row/col[4]"/></Action>
<org><xsl:value-of select="$row/col[2]"/></org>
<code><xsl:value-of select="$code"/></code>
<FieldLab>Acc<xsl:value-of select="."/></FieldLab>
<FieldVal><xsl:value-of select="$row/col[(1,5,6,7,3)[$p]]"/></FieldVal>
<FieldOrd><xsl:value-of select="."/></FieldOrd>
</Info>
</xsl:for-each>
</Account>
</xsl:template>
您可以通过多种方式将两个阶段串联起来。您可以在单个样式表中执行此操作(将第一个阶段的结果放在变量中,然后在第二个阶段处理它),或者您可以从shell脚本,Ant或XProc或xmlsh依次执行它们,或自定义Java应用程序。
答案 1 :(得分:1)
正如W3C所说:
以这种方式使用XSLT更加冗长,更不可靠,因为它不是为解析文本文件而设计的。虽然我已经包含了一个Python解决方案,正如@JimGarrison指出的那样,还有很多其他字符串I / O语言更适合。除非您有强烈的业务需求,必须使用XSLT,否则我强烈建议您查看下面的代码并将其翻译成您选择的语言。
我认为您已经问过一个经典XY Problem,所以我在Python中编写了一个替代版本,您可以在此处看到:http://codepad.org/JWNbqrwD。它不包括文件I / O,但这并不是一个非常棘手的更改。
一些事情,你的输出不是XML - 没有单个根元素,并且你Info
标签没有正确关闭,所以这个脚本也没有。
import re
from datetime import datetime
data = """Directory: sample/archive
Name: 20130613-T210002.TXT
---------------------------------------------------------------
"11FCK1GR0026" "G190" "FPB - OK Ship Pt" "A" "11" "XX" "02"
"11FCA1GR0034" "G980" "FPB -San Antonio" "A" "11" "XX" "02"
"11FCA1GR0034" "G160" "FPB -San Antonio" "A" "11" "XX" "02"
"""
output = ""
# Split on new lines start at line 3.
for line in data.split("\n")[3:]:
fields = re.findall('"([^"]*)"',line) #Find all
newAccount = ""
if len(fields) == 7:
action, org, code = fields[3],fields[2], "".join([fields[0],fields[3],fields[4]])
newAccount = "<Account>\n" + \
"\t<Action>%s</Action>\n" % action + \
"\t<org>%s</org>\n" % org + \
"\t<code>%s</code>\n" % code + \
"\t<FiscalYear>%s</FiscalYear>\n" % datetime.now().year
orderMap = [(1,0),(2,4),(3,5),(4,6),(5,2)]
for pos,fieldNum in orderMap:
newAccount += "\t<Info>\n" + \
"\t\t<Action>%s</Action>\n" % action + \
"\t\t<org>%s</org>\n" % org + \
"\t\t<code>%s</code>\n" % code + \
"\t\t<Fieldlab>Acc%s</Fieldlab>\n" % pos + \
"\t\t<FieldVal>%s</FieldVal>\n" % fields[fieldNum]+ \
"\t\t<FieldOrd>%s</FieldOrd>\n" % pos + \
"\t<Info>\n"
newAccount += "</Account>\n"
output += newAccount
print output