2013-06-24 91 views
0

我需要使用xslt從文本文件生成格式良好的XML結構。我是xslt轉型的新手,這對我來說看起來有些挑戰。 示例文本文件如下。我需要省略第一部分並將引號中的值映射到輸出xml文件。從文本文件生成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> 

任何人可以幫我生成此文件。提前致謝!

+4

雖然XSLT 2可以讀取非XML輸入,但您可能會發現使用腳本語言(如Python,Perl或Groovy)可以更輕鬆地完成此操作。 –

+1

如果你想避免學習新的技巧,那可能是真的,但Python(等)代碼不可能比下面顯示的XSLT代碼更簡單。 –

+1

@MichaelKay在一個更合適的語言中編碼並不一定是正確的,我認爲在W3C認爲XSLT是「一種語言」時,建議使用XSLT進行某些操作(字符串處理)是不明智的轉換XML文檔「不是通用文件。 – 2013-06-25 02:01:45

回答

2

我會在兩個階段做這個轉換(通過分解來簡化任務)。第一階段生成與原始文本同構的XML;第二階段重構XML。

第1階段是這樣的:

<xsl:template name="main"> 
<doc> 
    <xsl:for-each select="tokenize(unparsed-text('input.txt'), '\r?\n') 
          [starts-with(., '&quot;')]"> 
    <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應用程序。

+0

這個答案的問題是,我不認爲你所做的*比equivilent python/prel/etc ...更可讀,因爲它們是爲文件解析設計的腳本語言。 XSLT是(或應該是)關於轉換XML文檔。其次,通過使用XSLT,提問者現在被高度限制爲基於Java或CLI的解決方案,這使得在大型系統中導入或重用此代碼變得更加困難。 – 2013-06-24 23:30:02

+1

用戶要求提供XSLT 2.0解決方案,因爲XSLT 2.0非常適合我很樂意提供的任務。 Java相當普遍,因此XSLT 2.0也是如此。 –

+0

我同意文件解析是關鍵,但我不喜歡使用多種語言的想法。擴展模式表示法應該被指定爲具有聲明性方法,以便解析器將自動創建相應的XDM,然後允許XSLT或XQuery進行處理。 –

1

由於W3C狀態:

XSL Transformations (XSLT 2.0) is a language for transforming XML documents into other XML documents, text documents or HTML documents

以這種方式使用XSLT比較冗長,少reable,因爲它不是設計來解析文本文件。儘管我已經包含了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 
+1

這段代碼就像很多嘗試從不是爲工作而設計的語言編寫XML的嘗試一樣,如果輸入包含特殊字符(如&和<),則會產生不合格的XML。它就是這樣的代碼,解釋了爲什麼我們有這麼多人問StackOverflow如何修復不好的XML。 –

+1

還要注意,W3C的引用來自市場推廣,而不是來自規範本身。 XSLT 1.0規範有類似的句子,但它從2.0規範中被刪除,作爲語言功能增加的明確信號。 Java的營銷手段說它是用來編寫applet的...... –