如何使用可变条件将XSLT模板应用于节点副本(从先前的XML节点中提取)

时间:2011-09-17 21:58:12

标签: xml xslt xpath

我是XSLT转换的新手。我正在编写一些转换,以便重构在srcML中表达的代码,我正面临一个问题。我正在使用的XML输入如下所示:     

....
<function><type><name>void</name></type> <name>DrawHorizontal</name>
<parameter_list>(
    <param><decl><type><name>t_paper</name></type> <name>p</name></decl></param>,
    <param><decl><type><name>int</name></type> <name>x</name></decl></param>,
    <param><decl><type><name>int</name></type> <name>y</name></decl></param>)
 </parameter_list>
   <block>{.....
     <expr_stmt><expr>
       <name>
         <name>p</name>
         <index>[<expr><name>x</name></expr>]</index>
         <index>[<expr><name>y</name></expr>]</index>
       </name>.
       <name>hor</name>
       <operator>=</operator> 1
     </expr>;</expr_stmt>
  ...
  }</block>
</function>

我想要做的是,对于每个功能部分:

1)识别某种类型参数的名称(例如p类型为p_paper)

2)更改表达式语句,其中找到上一步中标识的参数()

输出应如下所示:

.....
<function><type><name>void</name></type> <name>DrawHorizontal</name>
<parameter_list>(
    <param><decl><type><name>t_paper</name></type> <name>p</name></decl></param>,
    <param><decl><type><name>int</name></type> <name>x</name></decl></param>,
    <param><decl><type><name>int</name></type> <name>y</name></decl></param>)
 </parameter_list>
   <block>{.....
     <expr_stmt><expr>
       <name>p</name>.
       <name>
         <name>data</name>
         <index>[<expr><name>x</name></expr>]</index>
         <index>[<expr><name>y</name></expr>]</index>
       </name>.
       <name>hor</name>
       <operator>=</operator> 1
     </expr>;</expr_stmt>
  ...
  }</block>
</function>

总之,我需要仅在找到特定类型的参数的地方转换expr_stmt节点(示例中为t_paper)。应该按原样复制文件的其余部分。

我的问题是我无法根据动态创建的条件(参数名称)将模板应用于特定部分。

一些不能正常工作的代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node() | @*">
   <xsl:copy>
      <xsl:apply-templates select="node() | @*" />
   </xsl:copy>
</xsl:template>

<xsl:template match="//function">
<xsl:choose>
       <xsl:when test="parameter_list/param/decl/type/name='t_paper'">
    <xsl:copy>
     <xsl:call-template name="transform-function" select="node()">
      <xsl:with-param name="appearance" select="parameter_list/param/decl/name" />
     </xsl:call-template>
        </xsl:copy> 
       </xsl:when>
       <xsl:otherwise>
         <function><xsl:apply-templates select="node()"/></function>
   </xsl:otherwise>
</xsl:choose>
 </xsl:template>

 <xsl:template name="transform-function">
<xsl:param name="appearance" />
<xsl:if test="//expr_stmt/expr/name/name=$appearance">
    substitution here
</xsl:if>
 </xsl:template>
</xsl:stylesheet>

如果有人能给我一个提示,我将非常感激。

如果您需要更多详细信息,请告诉我,因为这是我在SO的第一个问题。

干杯,

d

2 个答案:

答案 0 :(得分:1)

这个简单的转换(根本没有明确的条件):

<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="kParamByNameType" match="param"
  use="concat(decl/name, '+', decl/type/name)"/>

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

 <xsl:template match=
   "expr/name
         [key('kParamByNameType',
              concat(name, '+', 't_paper')
              )
         ]">
  <xsl:copy-of select="name"/>
  <name>
    <name>data</name>
    <xsl:apply-templates select="name/following-sibling::node()"/>
  </name>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档

<function>
    <type>
        <name>void</name>
    </type>
    <name>DrawHorizontal</name>
    <parameter_list>(     
        <param>
           <decl>
                    <type>
                        <name>t_paper</name>
                    </type>
                    <name>p</name>
       </decl>
        </param>,     
        <param>
            <decl>
                <type>
                    <name>int</name>
                </type>
                <name>x</name>
            </decl>
        </param>,     
        <param>
            <decl>
                <type>
                    <name>int</name>
                </type>
                <name>y</name>
            </decl>
        </param>)  
    </parameter_list>
    <block>{.....      
        <expr_stmt>
            <expr>
                <name>
                    <name>p</name>
                    <index>[
                        <expr>
                            <name>x</name>
                        </expr>]
                    </index>
                    <index>[
                        <expr>
                            <name>y</name>
                        </expr>]
                    </index></name>.        
                <name>hor</name>
                <operator>=</operator> 1      
            </expr>;
        </expr_stmt>   ...   }
    </block>
</function>

产生想要的结果

<function>
   <type>
      <name>void</name>
   </type>
   <name>DrawHorizontal</name>
   <parameter_list>(     
        <param>
         <decl>
            <type>
               <name>t_paper</name>
            </type>
            <name>p</name>
         </decl>
      </param>,     
        <param>
         <decl>
            <type>
               <name>int</name>
            </type>
            <name>x</name>
         </decl>
      </param>,     
        <param>
         <decl>
            <type>
               <name>int</name>
            </type>
            <name>y</name>
         </decl>
      </param>)  
    </parameter_list>
   <block>{.....      
        <expr_stmt>
         <expr>
            <name>p</name>
            <name>
               <name>data</name>
               <index>[
                        <expr>
                     <name>x</name>
                  </expr>]
                    </index>
               <index>[
                        <expr>
                     <name>y</name>
                  </expr>]
                    </index>
            </name>.        
                <name>hor</name>
            <operator>=</operator> 1      
            </expr>;
        </expr_stmt>   ...   }
    </block>
</function>

<强>解释

  1. 仅针对所请求类型的参数覆盖identity rule

  2. 使用key 方便地定义参数声明与其(名称,类型)之间的映射

答案 1 :(得分:0)

这是一个xsl:key元素/ key()函数回答

我不得不退出你的两步解决方案,找到一个可行的答案。我不知道你从哪里得到你的表达式语句,但我想这是来自C#/ .NET的东西。

在任何情况下,我都会看到你正在做的是包装一个类型,以便表达式改变:

p[x][y] to p.data[x][y]

如果是这种情况,我选择只在表达式的组件上匹配模板,而不是对整个函数应用不同的外观。然后有条件地在每个参数名称上,我查找类型以查看它是否是您正在寻找的那个。可以为要捕获的每种类型添加额外的“when”语句:

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

<!--  key('parambyname','p')/type/name eq 't_paper' -->
<xsl:key name="parambyname" match="parameter_list/param/decl" use="name"/>

<xsl:template match="//expr_stmt/expr//name">
   <xsl:choose>
      <xsl:when test="key('parambyname',text())/type/name eq 't_paper'">
       <xsl:copy>
                 <xsl:apply-templates select="./text()" />
       </xsl:copy>
       <xsl:text>.</xsl:text>
       <name>data</name>
       <xsl:apply-templates select="!text()"/>
      </xsl:when>
      <xsl:otherwise>
       <xsl:copy>
          <xsl:apply-templates select="node() | @*"/>
       </xsl:copy>
      </xsl:otherwise>
   </xsl:choose>
</xsl:template>

</xsl:stylesheet>