2011-11-20 64 views
3

我想找到一個更好的解決方案來轉換純文本(但與每個字段預定義的長度)爲XML。 例如,輸入文本可以是 「Testuser new york 10018」,前11個字符表示用戶名,接下來的12個字符表示城市,接下來的5個字符表示郵政編碼。 所以我需要從預定義字段長度的上述字符串形成一個XML。xslt是將文本轉換爲xml結構的好方法嗎?

我想2接近

  1. 定義的商業實體,並通過對輸入文本串功能填補了實體屬性,然後序列化成XML

  2. 預先定義的XML結構的實體,使用xslt導航到每個節點並使用輸入文本上的子字符串函數填充 的值。

回答

5

的語句:(XSLT)"isn't suitable for transforming from structured text to XML. "及本聲明"XSLTmusthave XML as the input document" **都是錯誤

我想2接近

  1. 定義的商業實體,並通過對輸入文本串功能填補了實體屬性,然後序列化實體 XML

  2. 預先定義xml結構,請使用xslt導航到每個節點並通過在輸入文本上使用子字符串函數來填充值。

事實上,方法2是很容易用XSLT來完成:

I. XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="/*/text()" name="processLines"> 
    <xsl:param name="pText" select="."/> 

    <xsl:if test="contains($pText, '&#xA;')"> 
    <xsl:variable name="vLine" select= 
    "substring-before($pText, '&#xA;')"/> 

    <user> 
     <name> 
     <xsl:value-of select= 
     "translate(substring-before($vLine, ' '),'_',' ')"/> 
     </name> 
     <city> 
     <xsl:value-of select= 
     "translate(substring-before(substring-after($vLine, ' '),' '), 
        '_', 
        ' ' 
        ) 
     "/> 
     </city> 
     <zipCode> 
     <xsl:value-of select= 
     "translate(substring-after(substring-after($vLine, ' '),' '), 
        '_', 
        ' ' 
        ) 
     "/> 
     </zipCode> 
    </user> 

    <xsl:call-template name="processLines"> 
     <xsl:with-param name="pText" select= 
     "substring-after($pText, '&#xA;')"/> 
    </xsl:call-template> 
    </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 

當這種轉變是在所施加的特別格式化的文本(包裹在一個單一的頂部元素中,以便形成良好 - 就像我們一樣升看到在XSLT 2.0這樣的包裝是不必要的):

<t>Testuser new_york 10018 
usera seattle 98000 
userb bellevue 98004 
userb redmond 98052 
</t> 

有用結果產生

<user> 
    <name>Testuser</name> 
    <city>new york</city> 
    <zipCode>10018</zipCode> 
</user> 
<user> 
    <name>usera</name> 
    <city>seattle</city> 
    <zipCode>98000</zipCode> 
</user> 
<user> 
    <name>userb</name> 
    <city>bellevue</city> 
    <zipCode>98004</zipCode> 
</user> 
<user> 
    <name>userb</name> 
    <city>redmond</city> 
    <zipCode>98052</zipCode> 
</user> 

  1. 這僅僅是一個演示如何完成任務。這就是爲什麼我不處理固定寬度的字段(甚至更容易),但空間分隔的值。

  2. 包含在任何值中的任何空格都以下劃線(或者我們選擇的任何字符輸入,我們知道這些字符永遠不會成爲任何值的一部分)在輸出時,任何下劃線都會被轉換爲真實空間

II XSLT 2.0溶液

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:variable name="vText" select= 
    "unparsed-text('file:///c:/temp/delete/delete.txt')"/> 

<xsl:variable name="vLines" select= 
    "tokenize($vText, '&#xD;?&#xA;')[normalize-space()]"/> 

<xsl:template match="/"> 
    <xsl:for-each select="$vLines"> 
    <xsl:variable name="vFields" select= 
    "tokenize(., ' ')[normalize-space()]"/> 
    <user> 
    <name> 
     <xsl:sequence select="translate($vFields[1], '_',' ')"/> 
    </name> 
    <city> 
     <xsl:sequence select="translate($vFields[2], '_',' ')"/> 
    </city> 
    <zipCode> 
     <xsl:sequence select="translate($vFields[3], '_',' ')"/> 
    </zipCode> 
    </user> 
    </xsl:for-each> 
</xsl:template> 
</xsl:stylesheet> 

當該變換被應用在任何XML文檔(未使用和實際ñ OT需要,如在XSLT 2.0,沒有必要爲具有源XML文檔)和如果文件C:\temp\delete\delete.txt

Testuser new_york 10018 
usera seattle 98000 
userb bellevue 98004 
userb redmond 98052 

再次有用,正確的結果產生

<user> 
    <name>Testuser</name> 
    <city>new york</city> 
    <zipCode>10018</zipCode> 
</user> 
<user> 
    <name>usera</name> 
    <city>seattle</city> 
    <zipCode>98000</zipCode> 
</user> 
<user> 
    <name>userb</name> 
    <city>bellevue</city> 
    <zipCode>98004</zipCode> 
</user> 
<user> 
    <name>userb</name> 
    <city>redmond</city> 
    <zipCode>98052</zipCode> 
</user> 

注意

  1. 使用標準的XSLT 2.0功能unparsed-text()

  2. 使用標準的XPath 2.0函數tokenize()

最後一點

最複雜的文本處理已在工業方式XSLT已經做完全。 The FXSL library包含一個通用LR(1) parsertweaked YACC that produces XML-formatted tables屬於輸入到該通用運行時LR(1)解析器。

使用此工具,我成功地爲built parsers對於像JSON和XPath 2.0這樣複雜的語言。

+0

非常感謝你的想法。我將嘗試使用您建議的xslt庫,並看看它的熱點 – testuser