2012-03-13 43 views
1

我有一个表模式,它具有一些元字段数据,我需要将其拉低到行级别。使用xsl:key检索同级:

所以这...

<tables> 
    <table name="T01"> 
     <columns> 
      <column name="F01"> 
       <heading>Field 1</heading> 
      </column > 
      <column name="F02"> 
       <heading>Field 2</heading> 
      </column> 
     </columns> 
     <rows> 
      <row> 
       <field name="F01">AAAAA</field> 
       <field name="F02">BBBBB</field> 
      </row> 
      <row> 
       <field name="F01">DDDDD</field> 
       <field name="F02">EEEEE</field> 
      </row> 
     </rows> 
    </table> 
    <table name="T02"> 
     <!-- ... --> 
    </table> 
</tables> 

应该成为这个...

<tables> 
    <table name="T01"> 
     <rows> 
      <row> 
       <field name="F01"> 
        <heading>Field 1</heading> 
        <value>AAAAA</value> 
       </field> 
       <field name="F02">      
        <heading>Field 2</heading> 
        <value>BBBBB</value> 
       </field> 
      </row> 
      <row> 
       <field name="F01"> 
        <heading>Field 1</heading> 
        <value>DDDDD</value> 
       </field> 
       <field name="F02">      
        <heading>Field 2</heading> 
        <value>EEEEE</value> 
       </field> 
      </row> 
     </rows> 
    </table> 
    <table name="T02"> 
     <!-- ... --> 
    </table> 
</tables> 

我相信有吨简单的方式与XSLT要做到这一点,但由于我的工具,我真的需要通过一个键()来检索列标题。因此,像这样......

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

    <!-- This won't work but if it did ... --> 
    <xsl:key name="field-heading" 
      match="../../columns/column/heading" 
      use="../@name" /> 

    <xsl:template match="@* | node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@* | node()"/> 
    </xsl:copy> 
    </xsl:template> 


    <xsl:template match="field"> 
    <field name="{@name}"> 
     <heading> 
     <xsl:value-of select="key('field-heading', @name)"/> 
     </heading> 
     <value> 
     <xsl:value-of select="."/> 
     </value> 
    </field> 
    </xsl:template> 

    <xsl:template match="columns"/> 

</xsl:stylesheet> 

但是在xsl:钥匙匹配属性不允许父轴,我不知道是否有任何其他方式使其适合。

回答

0

稍微简单的解决方案

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

<xsl:key name="kColByNames" match="column" use= 
    "concat(../../@name, '+', @name)"/> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="field"> 
    <xsl:copy> 
    <xsl:copy-of select="@*"/> 
    <heading> 
    <xsl:value-of select= 
     "key('kColByNames', concat(ancestor::table[1]/@name, '+', @name))"/> 
    </heading> 
    <value><xsl:value-of select="."/></value> 
    </xsl:copy> 
</xsl:template> 
<xsl:template match="columns"/> 
</xsl:stylesheet> 

当这个变换所提供的XML文档施加:

<tables> 
    <table name="T01"> 
     <columns> 
      <column name="F01"> 
       <heading>Field 1</heading> 
      </column> 
      <column name="F02"> 
       <heading>Field 2</heading> 
      </column> 
     </columns> 
     <rows> 
      <row> 
       <field name="F01">AAAAA</field> 
       <field name="F02">BBBBB</field> 
      </row> 
      <row> 
       <field name="F01">DDDDD</field> 
       <field name="F02">EEEEE</field> 
      </row> 
     </rows> 
    </table> 
    <table name="T02"> 
     <!-- ... --> 
    </table> 
</tables> 

有用,正确的结果产生

<tables> 
    <table name="T01"> 
     <rows> 
     <row> 
      <field name="F01"> 
       <heading>Field 1</heading> 
       <value>AAAAA</value> 
      </field> 
      <field name="F02"> 
       <heading>Field 2</heading> 
       <value>BBBBB</value> 
      </field> 
     </row> 
     <row> 
      <field name="F01"> 
       <heading>Field 1</heading> 
       <value>DDDDD</value> 
      </field> 
      <field name="F02"> 
       <heading>Field 2</heading> 
       <value>EEEEE</value> 
      </field> 
     </row> 
     </rows> 
    </table> 
    <table name="T02"><!-- ... --></table> 
</tables> 

说明:覆盖身份规则和使用复合密钥 - 一个column由其name识别属性和其祖父母tablename属性。

0

的主要问题是,关键定义的上下文是文档不是你使用的关键,因此定义应该是

<xsl:key name="field-heading" 
    match="/tables/table/columns/column/heading" 
    use="../@name" /> 

有一对夫妇在你的XML错别字的地方 - 这是我想应该是

<?xml version="1.0" encoding="iso-8859-1"?> 
<?xml-stylesheet type="text/xsl" href="C:/Users/morank/Documents/temp/code.xsl"?> 
<tables> 
    <table name="T01"> 
     <columns> 
      <column name="F01"> 
       <heading>Field 1</heading> 
      </column> 
      <column name="F02"> 
       <heading>Field 2</heading> 
      </column> 
     </columns> 
     <rows> 
      <row> 
       <field name="F01">AAAAA</field> 
       <field name="F02">BBBBB</field> 
      </row> 
      <row> 
       <field name="F01">DDDDD</field> 
       <field name="F02">EEEEE</field> 
      </row> 
     </rows> 
    </table> 
    <table name="T02"> 
     <!-- ... --> 
    </table> 
</tables> 

应用以下XSLT

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

    <!-- This won't work but if it did ... --> 
    <xsl:key name="field-heading" 
     match="/tables/table/columns/column/heading" 
     use="../@name" /> 

    <xsl:template match="@* | node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@* | node()"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="field"> 
     <field name='{@name}'> 
      <heading> 
       <xsl:value-of select="key('field-heading', @name)"/> 
      </heading> 
      <value> 
       <xsl:value-of select="."/> 
      </value> 
     </field> 
    </xsl:template> 

    <xsl:template match="columns"/> 

</xsl:stylesheet> 

给出所需的输出:

<?xml version="1.0" encoding="UTF-8"?> 
<?xml-stylesheet type="text/xsl" href="C:/Users/morank/Documents/temp/code.xsl"?><tables> 
    <table name="T01">   
     <rows> 
      <row> 
       <field name="F01"> 
        <heading>Field 1</heading> 
        <value>AAAAA</value> 
       </field> 
       <field name="F02"> 
        <heading>Field 2</heading> 
        <value>BBBBB</value> 
       </field> 
      </row> 
      <row> 
       <field name="F01"> 
        <heading>Field 1</heading> 
        <value>DDDDD</value> 
       </field> 
       <field name="F02"> 
        <heading>Field 2</heading> 
        <value>EEEEE</value> 
       </field> 
      </row> 
     </rows> 
    </table> 
    <table name="T02"> 
     <!-- ... --> 
    </table> 
</tables> 

请注意,我也改变了模板是标准的身份转换,并确保该字段的名字被复制

+0

查看我对DevNull的评论,并感谢更正。 – 2012-03-13 21:57:44

0

尝试使用这样的:

<xsl:key name="field-heading" 
    match="heading" 
    use="parent::column/@name" /> 

在这种情况下,../将不起作用,因为use路径不是从根开始的。


编辑

尝试创建使用table/@namecolumn/@name沿着钥匙。这应该使它独一无二。

XML输入(我希望这代表您的评论的问题。)

<tables> 
    <table name="T01"> 
    <columns> 
     <column name="F01"> 
     <heading>Field 1</heading> 
     </column> 
     <column name="F02"> 
     <heading>Field 2</heading> 
     </column> 
    </columns> 
    <rows> 
     <row> 
     <field name="F01">AAAAA</field> 
     <field name="F02">BBBBB</field> 
     </row> 
     <row> 
     <field name="F01">DDDDD</field> 
     <field name="F02">EEEEE</field> 
     </row> 
    </rows> 
    </table> 
    <table name="T02"> 
    <columns> 
     <column name="F01"> 
     <heading>Field A</heading> 
     </column> 
     <column name="F02"> 
     <heading>Field B</heading> 
     </column> 
    </columns> 
    <rows> 
     <row> 
     <field name="F01">11111</field> 
     <field name="F02">22222</field> 
     </row> 
     <row> 
     <field name="F01">44444</field> 
     <field name="F02">55555</field> 
     </row> 
    </rows> 
    </table> 
</tables> 

修改XSLT 1。0

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

    <!-- This won't work but if it did ... --> 
    <xsl:key name="field-heading" 
    match="heading" 
    use="concat(ancestor::table/@name,'+',parent::column/@name)" /> 

    <xsl:template match="@* | node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@* | node()"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="field"> 
    <field name="{@name}"> 
     <heading> 
     <xsl:value-of select="key('field-heading', concat(ancestor::table/@name,'+',@name))"/> 
     </heading> 
     <value> 
     <xsl:value-of select="."/> 
     </value> 
    </field> 
    </xsl:template> 

    <xsl:template match="columns"/> 

</xsl:stylesheet> 

XML输出

<tables> 
    <table name="T01"> 

     <rows> 
     <row> 
      <field name="F01"> 
       <heading>Field 1</heading> 
       <value>AAAAA</value> 
      </field> 
      <field name="F02"> 
       <heading>Field 2</heading> 
       <value>BBBBB</value> 
      </field> 
     </row> 
     <row> 
      <field name="F01"> 
       <heading>Field 1</heading> 
       <value>DDDDD</value> 
      </field> 
      <field name="F02"> 
       <heading>Field 2</heading> 
       <value>EEEEE</value> 
      </field> 
     </row> 
     </rows> 
    </table> 
    <table name="T02"> 

     <rows> 
     <row> 
      <field name="F01"> 
       <heading>Field A</heading> 
       <value>11111</value> 
      </field> 
      <field name="F02"> 
       <heading>Field B</heading> 
       <value>22222</value> 
      </field> 
     </row> 
     <row> 
      <field name="F01"> 
       <heading>Field A</heading> 
       <value>44444</value> 
      </field> 
      <field name="F02"> 
       <heading>Field B</heading> 
       <value>55555</value> 
      </field> 
     </row> 
     </rows> 
    </table> 
</tables> 
+0

只有当列/字段名称在所有表中唯一或至少共享相同的标题文本时,这才会起作用。我正朝着保险/假设后面走。但不是我期望的 – 2012-03-13 21:56:53

+0

@ryse - 我希望我能正确理解这个问题。请看看我的编辑,并让我知道如果这就是你要找的。 – 2012-03-13 22:16:05

+0

我认为这是我能得到的最接近的。我真的希望这不会改变'use'除了列/字段名称以外的其他任何东西,但是希望的方形插件似乎不适合XSLT的圆孔。 – 2012-03-14 15:38:37