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:
Overriding the identity rule just for parameters that are of the requested type.
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>
精彩评论