XSLT help

S

Scott Zabolotzky

I have the following XML sample:

<Component Name="A">
<Param Name="OptionEnabled" DataType="boolean">
<Default>true</Default>
</Param>
<Param Name="Size" DataType="unsignedInt"/>
<Param Name="Lifetime" DataType="unsignedInt">
<Default>5</Default>
</Param>
<Param Name="FullName" DataType="string"/>
<Param Name="Category" DataType="string">
<Default>Employee</Default>
</Param>
</Component>


I'm trying to generate an XSLT that will generate an HTML form
from the data. I'm having a problem figuring out how to use the
child element <Default>, if present, when generating a control for
each <Param> element.

Basically, if a <Param> element has a child element of <Default>
I want to use that to set the value of the control being created
for the <Param> element.

I have the following rule for <Param>:

<xsl:template match="Param">
<tr>
<td valign="top">
<xsl:value-of select="@Name" />
</td>
<td>
<xsl:if test="@DataType='boolean'">
<asp:CheckBox id="{@Name}" runat="server" />
</xsl:if>
<xsl:if test="@DataType='string'">
<asp:TextBox id="{@Name}" runat="server"></asp:TextBox>
</xsl:if>
<xsl:if test="@DataType='unsignedInt'">
<asp:TextBox id="{@Name}" runat="server"></asp:TextBox>
</xsl:if>
</td>
<xsl:apply-templates/>
</tr>
</xsl:template>

but I can't figure out how to reference the child element (if present)
to set the value of the various controls.

Can this be done?
 
S

Soren Kuula

Scott said:
I have the following XML sample:

<cut/>

Without warranty:
<xsl:template match="Param">
<tr>
<td valign="top">
<xsl:value-of select="@Name" />
</td>
<td>
<xsl:if test="@DataType='boolean'">
<asp:CheckBox id="{@Name}" runat="server">
<xsl:attribute name="value">
<xsl:value-of select="Default/text()"/>
said:
</xsl:if>
<xsl:if test="@DataType='string'">
<asp:TextBox id="{@Name}" runat="server"></asp:TextBox>
</xsl:if>
<xsl:if test="@DataType='unsignedInt'">
<asp:TextBox id="{@Name}" runat="server"></asp:TextBox>
</xsl:if>
</td>
<xsl:apply-templates/>
</tr>
</xsl:template>

but I can't figure out how to reference the child element (if present)
to set the value of the various controls.

Interesting. You use XSLT to customize server script. I use server
script to customize XSLT ;)

Maybe we could together come up with WMCCG (World's Most Confusing Code
Generation) -- XSLT that generates ASP/JSP that generates XSLT that is
run at the client ... ;)

Søren
 
S

Scott Zabolotzky

Soren Kuula said:
<xsl:attribute name="value">
<xsl:value-of select="Default/text()"/>
</xsl:attribute>

Thanks. That works for text boxes where the text value is the
content of the <asp:TextBox> element. How about the checkbox
where the format is

<asp:CheckBox id="chk" Checked="[true|false]"/>

So if the <Param> has the <Default> child element:

<Param Name="Test" DataType="boolean">
<Default>true</Default>
</Param>

it would result in

<asp:CheckBox id="Test" Checked="true"/>

but if the <Param> does not have the <Default> child element:

<Param Name="Test" DataType="boolean"/>

it would result in

<asp:CheckBox id="Test"/>


Any ideas how I wold modify my XSLT template to accomplish this?

<xsl:if test="@DataType='boolean'">
<asp:CheckBox id="{@Name}" runat="server" />
</xsl:if>
 
S

Soren Kuula

Scott said:
Soren Kuula <[email protected]> writes:

(se above mail for question)
Any ideas how I wold modify my XSLT template to accomplish this?

Well, you have to look for the Default element in the template that
matches its parent element. If it is there, you take one action, and if
not, another. By just recursing (applying a template on) the Default
element, you can not stitch in any action for when it is _not_ present
(which is what you want).

<xsl:template match=....>
<blah>
<xsl:attribute name=".....">
<xsl:choose>
<xsl:when test="child::Default"> <!-- eval. to true if there is a
Default child elem of the context node -->
<xsl:value-of select="child::Default/text()"/>
</xsl:when>
<xsl:eek:therwise>false(or whatever you want as default of
default)</xsl:eek:therwise>
</xsl:choose>
</xsl:attribute>
</blah>
</xsl:template>
 
S

Scott Zabolotzky

Same app, next problem:

I have the following XML

<Component Name="Component1">
<Param Name="Param1" DataType="string"/>
<Group Name="Group1">
<Param Name="Param2" DataType="unsignedInt">
<Default>512</Default>
</Param>
<Param Name="Param3" DataType="string"/>
</Group>
</Component>


and the following XSLT portion to create ASP.NET controls based on
the XML.

<xsl:template match="Param">
<tr>
<td>
<xsl:if test="@DataType='string'">
<asp:TextBox id="{@Name}" runat="server">
<xsl:value-of select="Default/text()"/>
</asp:TextBox>
</xsl:if>
<xsl:if test="@DataType='unsignedInt'">
<asp:TextBox id="{@Name}" runat="server">
<xsl:value-of select="Default/text()"/>
</asp:TextBox>
</xsl:if>
</td>
</tr>
</xsl:template>

The problem I'm trying to solve is how to have the name of the
ASP.NET control be a combination of the
Component/Group(if present)/Param names. In the above example
I'd like to end up with controls named as follows:

Param1: "Component1_Param1"
Param2: "Component1_Group1_Param2"
Param3: "Component1_Group1_Param3"

I can't figure out how to include the parent's node name in
the control name. Solving the added complexity of an optional
entry in the hierarchy (the <Group> element) is even more of a
mystery to me.

Scott
 
J

Joe Kesselman

I can't figure out how to include the parent's node name in
the control name

One of several ways to obtain that value:
<xsl:value-of select="localname(..)"/>

You seen to want all the ancestors, though, rather than just the
immediate parent. So you might want to look at my old pseudo-xpath
generator template; a minor change to its syntax would produce the sorts
of strings you're looking for. It appears in

http://www.ibm.com/developerworks/xml/library/x-styless2/

That two-part series also illustrates a bunch of other useful stylesheet
tricks, along with the concept of using stylesheets to generate and
alter other stylesheets.

(BTW, though it isn't particularly relevant for the current question:
the simplest trick for generating "real" namespace-aware XPaths would be
to use predicates rather than named steps. I realized that after the
article was published, unfortunately, and I haven't found a good idea
for a new mini-series that would give me an excuse to post that version.)
 
P

p.lepin

Scott said:
I have the following XML

<Component Name="Component1">
<Param Name="Param1" DataType="string"/>
<Group Name="Group1">
<Param Name="Param2" DataType="unsignedInt">
<Default>512</Default>
</Param>
<Param Name="Param3" DataType="string"/>
</Group>
</Component>


and the following XSLT portion to create ASP.NET controls
based on the XML.

<xsl:template match="Param">
<tr>
<td>
<xsl:if test="@DataType='string'">
<asp:TextBox id="{@Name}" runat="server">
<xsl:value-of select="Default/text()"/>
</asp:TextBox>
</xsl:if>
<xsl:if test="@DataType='unsignedInt'">
<asp:TextBox id="{@Name}" runat="server">
<xsl:value-of select="Default/text()"/>
</asp:TextBox>
</xsl:if>
</td>
</tr>
</xsl:template>

The problem I'm trying to solve is how to have the name
of the ASP.NET control be a combination of the
Component/Group(if present)/Param names. In the above
example I'd like to end up with controls named as
follows:

Param1: "Component1_Param1"
Param2: "Component1_Group1_Param2"
Param3: "Component1_Group1_Param3"

I can't figure out how to include the parent's node name
in the control name. Solving the added complexity of an
optional entry in the hierarchy (the <Group> element) is
even more of a mystery to me.

Keeping in mind that I'm not an XSLT expert, the following
should work:

Define an attribute set:

<xsl:attribute-set name="idParam">
<xsl:attribute name="id">
<xsl:choose>
<xsl:when test="ancestor::Group[last()]/@Name">
<xsl:value-of select="
concat(ancestor::Component[last()]/@Name,'_',
ancestor::Group[last()]/@Name,'_',
@Name)"/>
</xsl:when>
<xsl:eek:therwise>
<xsl:value-of select="
concat(ancestor::Component[last()]/@Name,'_',
@Name)"/>
</xsl:eek:therwise>
</xsl:choose>
</xsl:attribute>
</xsl:attribute-set>

After that, use xsl:use-attribute-sets="idParam" instead of
id="{@Name}". Naturally, this will only work if you don't
have nested <Component>s/<Group>s.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top