Page 1 of 1

XSLT problem

Posted: Thu Aug 10, 2006 3:21 pm
by panpilulu
Hello,

I have this input file that I want to transform:

Code: Select all

<definition name="fr.inria.test.clientServerComp" extends="fr.inria.test.rootType">

<component name="client" definition="fr.inria.test.client" />
<component name="more" definition="fr.inria.test.more" >
<component name="inMore">
<interface name="blabla" signature="olala"></interface>
<component name="inInMore-1">
<interface name="blabla" signature="olala"></interface>
</component>
<component name="inInMore-2">
<interface name="blabla" signature="olala"></interface>
</component>
</component>
<component name="inMore-second">
<interface name="blabla" signature="olala"></interface>
</component>
</component>
<component name="server" definition="fr.inria.test.server" />
<component name="inMore" definition="fr.inria.test.more"/>
</component>

<binding client="this.runnableItf" server="client.runnableItf" />
<binding client="client.print" server="server.print" />

</definition>

I have this additional xml file:

Code: Select all

<fractal-deployment>

<real-host name="Belote">
<virtual-host name="VH2" type="jvm">
<execution-context name="EC2" >
<content>
<component-name>server</component-name>
</content>
</execution-context>
</virtual-host>
<ip>138.96.64.61</ip>
</real-host >

<real-host name="Parlote">
<virtual-host name="VH1" type="jvm">
<execution-context name="EC1" >
<content>
<component-name>client</component-name>
<component-name>inMore</component-name>
</content>
</execution-context>
</virtual-host>
</real-host>

</fractal-deployment>
The goal of the XSLT is to insert virtual-node element with attribute name and value of this attribute equal of the corresponding execution context, in the component elements. The result after my XSLT transformation is:

Code: Select all

<definition name="fr.inria.test.clientServerComp" extends="fr.inria.test.rootType">

<component name="client" definition="fr.inria.test.client" >
<virtual-node name="EC1">
</component>
<component name="more" definition="fr.inria.test.more" >
<component name="inMore">
<interface name="blabla" signature="olala"></interface>
<component name="inInMore-1">
<interface name="blabla" signature="olala"></interface>
</component>
<component name="inInMore-2">
<interface name="blabla" signature="olala"></interface>
</component>
<virtual-node name="EC1">
</component>
<component name="inMore-second">
<interface name="blabla" signature="olala"></interface>
</component>
</component>
<component name="server" definition="fr.inria.test.server" />
<component name="inMore" definition="fr.inria.test.more"/>
<virtual-node name="EC2">
</component>

<binding client="this.runnableItf" server="client.runnableItf" />
<binding client="client.print" server="server.print" />

</definition>

That is what i managed to do with the folowing XSL :

Code: Select all

<xsl:transform  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:variable name="depl_file" select="document('../data/deployfractal.xml')"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//component">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
<xsl:variable name="comp_name" select="$depl_file//real-host/virtual-host/execution-context/content/component-name/text()"/>
<xsl:if test="current()/@name=$comp_name">
<xsl:element name="virtual-node">
<xsl:attribute name="name">
<xsl:value-of select="$depl_file//real-host/virtual-host/execution-context[content/component-name/text() = current()/@name]/@name"/>
</xsl:attribute>
</xsl:element>
</xsl:if>
</xsl:copy>
</xsl:template>
</xsl:transform>


But the problem is that there is difference between the component inMore in more and the component inMore in server. So I want to reference the components in the deployment xml file like this :

<component-name>server/inMore</component-name>
<component-name>more/inMore</component-name>
<component-name>more/inMore/inInMore-2</component-name>

The problem is that I dont know how to modify the XSLT to do now the insertion of virtual-node-s correctly.
Do you have any suggestions?
One particular problem that I have is that I dont know how to reference for example ONLY the second child component of the root element. "child::component[position()=2]" returns to me not only the component "more" but also the second component in it "inMore-second".

Violeta

Posted: Fri Aug 11, 2006 12:29 am
by jkmyoung
/*/*[2]

Does this xpath work?

Posted: Fri Aug 11, 2006 11:30 am
by panpilulu
Almost!
More precisely:
/*/component[2]

Thank you!

Re: XSLT problem

Posted: Fri Aug 11, 2006 12:20 pm
by sorin_ristache
Hello,
panpilulu wrote:One particular problem that I have is that I dont know how to reference for example ONLY the second child component of the root element. "child::component[position()=2]" returns to me not only the component "more" but also the second component in it "inMore-second".
I am not sure what you mean by only the second child component of the root element. A node returned by an XPath expression always includes all the child nodes of that node. That is the "more" component (<component name="more" definition="fr.inria.test.more">) always includes the "inMore-second" component (<component name="inMore-second">).
panpilulu wrote:I have this input file that I want to transform:
...
I have this additional xml file:
...
The result after my XSLT transformation is:
...
That is what i managed to do with the folowing XSL :
...
The result that I get with your sample files has a couple of differences. It contains

Code: Select all

    <component name="server" definition="fr.inria.test.server">
<virtual-node name="EC2"/>
</component>
<component name="inMore" definition="fr.inria.test.more">
<virtual-node name="EC1"/>
</component>
instead of

Code: Select all

    <component name="server" definition="fr.inria.test.server"/>
<component name="inMore" definition="fr.inria.test.more"/>
<virtual-node name="EC2"/>
Please post the expected result file for the 2 given XML files and the XSL file.
panpilulu wrote:So I want to reference the components in the deployment xml file like this :

<component-name>server/inMore</component-name>
<component-name>more/inMore</component-name>
<component-name>more/inMore/inInMore-2</component-name>
Also post the final form of the input files including deployfractal.xml.

Regards,
Sorin

Posted: Fri Aug 11, 2006 12:56 pm
by panpilulu
Sorry my first post is not very clear and even contains an error.
Thank you Sorin. I will explain. So we keep the first file.

Code: Select all

<definition name="fr.inria.test.clientServerComp" extends="fr.inria.test.rootType">

<component name="client" definition="fr.inria.test.client" />
<component name="more" definition="fr.inria.test.more" >
<component name="inMore">
<interface name="blabla" signature="olala"></interface>
<component name="inInMore-1">
<interface name="blabla" signature="olala"></interface>
</component>
<component name="inInMore-2">
<interface name="blabla" signature="olala"></interface>
</component>
</component>
<component name="inMore-second">
<interface name="blabla" signature="olala"></interface>
</component>
</component>
<component name="server" definition="fr.inria.test.server" />
<component name="inMore" definition="fr.inria.test.more"/>
</component>

<binding client="this.runnableItf" server="client.runnableItf" />
<binding client="client.print" server="server.print" />

</definition>
We modify the second

Code: Select all

<fractal-deployment>

<real-host name="Belote">
<virtual-host name="VH2" type="jvm">
<execution-context name="EC2" >
<content>
<component-name>server/inMore</component-name>
</content>
</execution-context>
</virtual-host>
<ip>138.96.64.61</ip>
</real-host >

<real-host name="Parlote">
<virtual-host name="VH1" type="jvm">
<execution-context name="EC1" >
<content>
<component-name>client</component-name>
<component-name>more/inMore/inInMore-1</component-name>
</content>
</execution-context>
</virtual-host>
</real-host>

</fractal-deployment>
The expected result

Code: Select all

<definition name="fr.inria.test.clientServerComp" extends="fr.inria.test.rootType">

<component name="client" definition="fr.inria.test.client" />
<virtual-node name="EC1">
</component>
<component name="more" definition="fr.inria.test.more" >
<component name="inMore">
<interface name="blabla" signature="olala"></interface>
<component name="inInMore-1">
<interface name="blabla" signature="olala"></interface>
<virtual-node name="EC1">
</component>
<component name="inInMore-2">
<interface name="blabla" signature="olala"></interface>
</component>
</component>
<component name="inMore-second">
<interface name="blabla" signature="olala"></interface>
</component>
</component>
<component name="server" definition="fr.inria.test.server" />
<component name="inMore" definition="fr.inria.test.more"/>
<virtual-node name="EC2">
</component>
</component>

<binding client="this.runnableItf" server="client.runnableItf" />
<binding client="client.print" server="server.print" />

</definition>
I wold like to modify the xsl file to do this....

Posted: Fri Aug 11, 2006 2:13 pm
by panpilulu
I think I found a way :lol:

Code: Select all

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

<xsl:variable name="depl_file" select="document('../data/deployfractal.xml')"/>

<xsl:template match="node()|@*">

<xsl:copy>

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

</xsl:copy>

</xsl:template>

<xsl:template match="//component">

<xsl:copy>

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

<xsl:variable name="comp_name_depl" select="$depl_file//real-host/virtual-host/execution-context/content/component-name/text()"/>

<xsl:variable name="comp_name_fract">

<xsl:if test="current()/parent::component">

<xsl:for-each select="current()/ancestor::component">

<xsl:value-of select="concat(current()/@name,'/')"/>

</xsl:for-each>

</xsl:if>

<xsl:value-of select="current()/@name"/>

</xsl:variable>

<xsl:if test="$comp_name_fract=$comp_name_depl">

<xsl:element name="virtual-node">

<xsl:attribute name="name">

<xsl:value-of select="$depl_file//real-host/virtual-host/execution-context[content/component-name/text() = $comp_name_fract]/@name"/>

</xsl:attribute>

</xsl:element>

</xsl:if>

</xsl:copy>

</xsl:template>

</xsl:transform>

:lol:

Thanks to all of you!

Posted: Fri Aug 11, 2006 3:41 pm
by sorin_ristache
Hello Violeta,

You can find below a more compact and simple stylesheet which uses XSLT 2.0. I made the comp_name variable global because it does not depend on the context element of the template so it should be computed only once. You have to apply an XSLT 2.0 processor, for example Saxon 8B.

Code: Select all

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

<xsl:variable name="depl_file" select="document('../data/deployfractal.xml')"/>
<xsl:variable name="comp_name" select="$depl_file//real-host/virtual-host/execution-context/content/component-name"/>

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

<xsl:template match="component">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
<xsl:variable name="complete_name"
select="string-join(for $i in ancestor-or-self::component return $i/@name, '/')"/>
<xsl:if test="$complete_name=$comp_name">
<xsl:variable name="virtual_node_name"
select="for $i in $comp_name return if ($i=$complete_name) then $i/../../@name else ()">
</xsl:variable>
<virtual-node name="{$virtual_node_name}"/>
</xsl:if>
</xsl:copy>
</xsl:template>
</xsl:transform>
Regards,
Sorin