开发者

How to apply an XSLT template to a node copy using variable conditions (extracted from a previous XML node)

I am new to XSLT transformations. I am writing some transformations in order to refactor code expressed in srcML and I am facing a problem. The XML input I am working with looks like this:

....
<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>

What I want to do is, for each function section:

1) Identify the name of the parameters of a certain type (p of type t_paper for example)

2) Change the expression statement where the parameters, identified in the previous step, are found ()

The output should look like this:

.....
<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&g开发者_运维技巧t;</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>

In summary, I need to transform expr_stmt nodes only where parameters of a certain type are found (t_paper in the example). The rest of the file should be copied as it is.

My problem is that I am not able to apply templates to that specific sections based on the dynamically created conditions (the names of the parameters).

Some NOT working code is the following:

<?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>

I would be very grateful if someone could give me a hint.

Please let me know if you need more details as this is my first question in SO.

Cheers,

D.


This simple transformation (no explicit conditionals at all):

<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>

when applied on the provided XML document:

<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>

produces the wanted result:

<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>

Explanation:

  1. Overriding the identity rule just for parameters that are of the requested type.

  2. Using a key to conveniently define the mapping between a parameter declaration and its (name, type)


This is an xsl:key element/key() function answer

I had to step back from your two step solution to find a workable answer. I don't know where you're getting your expression statement from, but I suppose it is something from C#/.NET.

In any case I see that what you are doing is wrapping a type so that the expressions change from:

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

If that's the case, instead of applying different appearances to the overall function, I chose to just have templates match on components of the expression. Then conditionally on each parameter name, I lookup the type to see if it is the one you are looking for. Additional 'when' statements can be added for each type you want to catch:

<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>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜