2013-10-07 78 views
0

我有類似下面的示例XML輸入:XSL 1.0格式表格拆分值

<table name="Table1"> 
<fields> 
    <field name="Field1" /> 
    <field name="Field2" /> 
    <field name="Field3" /> 
    <field name="Field4" /> 
</fields> 
<data> 
    <row value="2,Description1,A,AA" /> 
    <row value="3,Description2,B,BB" /> 
    <row value="7,Description3,C,CC" /> 
</data> 
</table> 
<table name="Table2"> 
<fields> 
    <field name="Field7" /> 
    <field name="Field8" /> 
    <field name="Field9" /> 
</fields> 
<data> 
    <row value="Q,Description7,A" /> 
    <row value="W,Description8,B" /> 
    <row value="X,Description9,C" /> 
</data> 
</table> 

請注意,我可以有不同數量的字段,但行值的許多表包含始終方面的準確數字需要。

預期的結果是這樣的輸出:

<ListOfTable1> 
<item> 
    <Field1>2</Field1> 
    <Field2>Description1</Field2> 
    <Field3>A</Field3> 
    <Field4>AA</Field4> 
</item> 
<item> 
    <Field1>3</Field1> 
    <Field2>Description2</Field2> 
    <Field3>B</Field3> 
    <Field4>BB</Field4> 
</item> 
<item> 
    <Field1>7</Field1> 
    <Field2>Description3</Field2> 
    <Field3>C</Field3> 
    <Field4>CC</Field4> 
</item> 
</ListOfTable1> 

<ListOfTable2> 
<item> 
    <Field7>Q</Field7> 
    <Field8>Description7</Field8> 
    <Field9>A</Field9> 
</item> 
<item> 
    <Field7>W</Field7> 
    <Field8>Description8</Field8> 
    <Field9>B</Field9> 
</item> 
<item> 
    <Field7>X</Field7> 
    <Field8>Description9</Field8> 
    <Field9>C</Field9> 
</item> 
</ListOfTable2> 

我僅可以使用嚴格XSLT 1.0不幸 無需外部的功能或引用

我已經使用第三溶液的略加修改的版本建議

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:template match="//table"> 
    <xsl:value-of disable-output-escaping="yes" select="concat('&lt;ListOf',@name,'&gt;')" /> 
    <xsl:apply-templates /> 
    <xsl:value-of disable-output-escaping="yes" select="concat('&lt;/ListOf',@name,'&gt;')" /> 
    </xsl:template> 

    <xsl:template match="table/data/row"> 
    <item> 
     <xsl:call-template name="fldsplit"> 
     <xsl:with-param name="f" select="@value" /> 
     <xsl:with-param name="set" select="//fields/field" /> 
     </xsl:call-template> 
    </item> 
    </xsl:template> 

    <xsl:template name="fldsplit"> 
    <xsl:param name="f" /> 
    <xsl:param name="set"/> 
    <xsl:variable name="bfc" select="substring-before($f,',')"/> 
    <xsl:variable name="afc" select="substring-after($f,',')"/> 
    <xsl:element name="{$set/@name}"> 
     <xsl:choose> 
     <xsl:when test="$bfc"> 
      <xsl:value-of select="$bfc"/> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:value-of select="$f"/> 
     </xsl:otherwise> 
     </xsl:choose> 
    </xsl:element> 
    <xsl:if test="$afc"> 
     <xsl:call-template name="fldsplit"> 
     <xsl:with-param name="f" select="$afc"/> 
     <xsl:with-param name="set" select="$set/following-sibling::*" /> 
     </xsl:call-template> 
    </xsl:if> 
    </xsl:template> 

</xsl:stylesheet> 

但我有第二個表(或任何其他我添加到輸入)的問題,那就是字段名稱repeat themselve ■從字段1總是在啓動,而我希望使用特定字段爲每個表解析的

這是電流輸出(錯誤)

<?xml version="1.0" encoding="UTF-8"?> 

<ListOfTable1> 
    <item><Field1>2</Field1><Field2>Description1</Field2><Field3>A</Field3><Field4>AA</Field4></item> 
    <item><Field1>3</Field1><Field2>Descritpion2</Field2><Field3>B</Field3><Field4>BB</Field4></item> 
    <item><Field1>7</Field1><Field2>Description3</Field2><Field3>C</Field3><Field4>CC</Field4></item> 
</ListOfTable1> 
<ListOfTable2> 
    <item><Field1>Q</Field1><Field2>Description7</Field2><Field3>A</Field3></item> 
    <item><Field1>W</Field1><Field2>Description8</Field2><Field3>B</Field3></item> 
    <item><Field1>X</Field1><Field2>Description9</Field2><Field3>C</Field3></item> 
</ListOfTable2> 
+0

嘿,如果你多次改變了初始條件,那麼這不是一個問題,它是一個「請做我的工作」! –

+0

對不起Orabig,實際上我沒有改變條件,因爲初始結構解析是相同的,但是在文件內部重複。像其他人一樣,您的建議可以正常工作,但目前所有人都以不同的方式管理字段和行。我試圖繞過這個騎自行車通過表,但到目前爲止沒有得到解決方案 – AndreaPappy

回答

0

如果可以肯定的是,在列值的唯一逗號是分割域的那些(即沒有像「"\,"」這樣的「逃脫」機制),並且每行都會有正確數量的字段,那麼遞歸方法就可以工作。我在這裏假設有一個名爲root的根元素包含您的table元素,以便使輸入格式良好。

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

    <xsl:template match="/"> 
    <data> 
     <xsl:apply-templates select="root/table" /> 
    </data> 
    </xsl:template> 

    <xsl:template match="table"> 
    <xsl:element name="ListOf{@name}"> 
     <xsl:apply-templates select="data/row"/> 
    </xsl:element> 
    </xsl:template> 

    <xsl:template match="row"> 
    <!-- add a trailing comma to the value so we don't lose the last field --> 
    <xsl:variable name="val" select="concat(@value, ',')" /> 
    <item> 
     <!-- use just the fields that belong to this table --> 
     <xsl:apply-templates select="../../fields/field[1]"> 
     <xsl:with-param name="thisVal" select="substring-before($val, ',')" /> 
     <xsl:with-param name="rest" select="substring-after($val, ',')" /> 
     </xsl:apply-templates> 
    </item> 
    </xsl:template> 

    <xsl:template match="field"> 
    <xsl:param name="thisVal"/> 
    <xsl:param name="rest"/> 

    <xsl:element name="{@name}"> 
     <xsl:value-of select="$thisVal" /> 
    </xsl:element> 

    <xsl:apply-templates select="following-sibling::field[1]"> 
     <xsl:with-param name="thisVal" select="substring-before($rest, ',')" /> 
     <xsl:with-param name="rest" select="substring-after($rest, ',')" /> 
    </xsl:apply-templates> 
    </xsl:template> 
</xsl:stylesheet> 

這裏的竅門是,我們生成應用模板又將field元素<Field1>等元素。因此,不需要任何明確的條件(ifchoose),因爲當following-sibling::field[1]不再選擇任何內容時,遞歸將自動停止在最後一個字段。

+0

@AndreaPappy我已經調整了我的答案,以處理同一文檔中的多個表格,就像您最近的編輯一樣。 –

1

那麼,這應該按預期工作:

<xsl:template match="/"> 
    <result> 
     <xsl:apply-templates select="//row"/> 
    </result> 
</xsl:template> 

<xsl:template match="row"> 
    <xsl:variable name="field1" select="substring-before(@value,',')"/> 
    <xsl:variable name="field2" select="substring-after(@value,',')"/> 
    <item> 
     <Field1><xsl:value-of select="$field1"/></Field1> 
     <Field2><xsl:value-of select="$field2"/></Field2> 
    </item> 
</xsl:template> 

由於你可以看到,我沒有使用你的部分(btw,Field2的type =「int」似乎不適合樣本),因爲我不知道如何。 它應該是一些領域? (如果有可能的字段未定義的號碼,然後遞歸的解決辦法是必要的...)


編輯:

好吧,我設法寫一個解決方案與任意數量的工作田:

<?xml version='1.0'?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

<xsl:key name="allfields" match="field" use="count(preceding-sibling::field) + 1"/> 

<xsl:template match="/"> 
    <result> 
     <xsl:apply-templates select="//row"/> 
    </result> 
</xsl:template> 

<xsl:template match="row"> 
    <item> 
    <xsl:call-template name="row"> 
     <xsl:with-param name="value" select="@value"/> 
     <xsl:with-param name="pos" select="1"/> 
    </xsl:call-template> 
    </item> 
</xsl:template> 

<xsl:template name="row"> 
    <xsl:param name="value"/> 
    <xsl:param name="pos"/> 
    <xsl:variable name="field1"> 
     <xsl:choose> 
      <xsl:when test="contains($value,',')"> 
       <xsl:value-of select="substring-before($value,',')"/> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:value-of select="$value"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:variable> 
    <xsl:variable name="fieldNext" select="substring-after($value,',')"/> 
    <xsl:variable name="fieldName" select="key('allfields',$pos)/@name"/> 
     <xsl:element name="{$fieldName}"> 
      <xsl:value-of select="$field1"/> 
     </xsl:element> 
     <xsl:if test="not($fieldNext='')"> 
      <xsl:call-template name="row"> 
       <xsl:with-param name="value" select="$fieldNext"/> 
       <xsl:with-param name="pos" select="$pos + 1"/> 
      </xsl:call-template> 
     </xsl:if> 
</xsl:template> 
</xsl:stylesheet> 

這個節目如何XSLT1.0非常不適合這樣的事情......

0

這裏是一個可以處理多個字段,假定它有相應數量的解決方案由分隔的字段,

<xsl:template match="/"> 
    <result> 
    <xsl:apply-templates /> 
    </result> 
    </xsl:template> 

    <xsl:template match="table"> 
    <xsl:element name="ListOf{@Name}"> 
     <xsl:apply-templates /> 
    </xsl:element> 
    </xsl:template> 


    <xsl:template match="data/row"> 
    <item> 
     <xsl:call-template name="fldsplit"> 
     <xsl:with-param name="f" select="@value" /> 
     <xsl:with-param name="set" select="//fields/field" /> 
     </xsl:call-template> 
    </item> 
    </xsl:template> 

    <xsl:template name="fldsplit"> 
    <xsl:param name="f" /> 
    <xsl:param name="set"/> 
    <xsl:variable name="bfc" select="substring-before($f,',')"/> 
    <xsl:variable name="afc" select="substring-after($f,',')"/> 
    <xsl:element name="{$set/@name}"> 
     <xsl:choose> 
     <xsl:when test="$bfc"> 
      <xsl:value-of select="$bfc"/> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:value-of select="$f"/> 
     </xsl:otherwise> 
     </xsl:choose> 
    </xsl:element> 
    <xsl:if test="$afc"> 
     <xsl:call-template name="fldsplit"> 
     <xsl:with-param name="f" select="$afc"/> 
     <xsl:with-param name="set" select="$set/following-sibling::*" /> 
     </xsl:call-template> 
    </xsl:if> 
    </xsl:template> 
+0

我一直在使用你的解決方案,它幾乎是完美的,但我不得不復習一點輸入文件,所以我有一個小問題與字段名稱。請您詳細解釋一下您的解決方案,以便使用爲可能的輸入表分隔的字段名稱?謝謝 – AndreaPappy