jktravis
jktravis

Reputation: 1568

How do I get the node name of parameter in XSLT template?

I'm trying to update some XSLT to accomodate a new XML input format. The new structure pretty much breaks my former template logic, but I'm trying to keep from having to rewrite the whole thing over.

Essentially, I'd like to grab the name of a template parameter, remove a prefix, and use the result in an <xsl:value-of/>. For example:

<!-- calling location -->
<xsl:call-template name="myTemplate">
    <xsl:with-param name="field" select="Name"/>
</xsl:call-template>

<!-- template to do the processing. -->
<xsl:template name="myTemplate">
    <xsl:param name="field"/>
    <xsl:variable name="fieldName" select="replace($field, 'Prefix', '')"/>
    <xsl:value-of select="$fieldName"/>
</xsl:template>

The context.

This is more of a over all since I have been asked to provide both the essence of the question and the over all context. A simplified version of my stylesheet can bee seen below:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:variable name="delimiter" select="','" />
    <xsl:variable name="newline" select="'&#xa;'" />

    <xsl:template match="/root">
        <xsl:apply-templates select="entry"/>
        <xsl:apply-templates select="entry/Dependents"/>
    </xsl:template>

    <xsl:template match="entry">
        <xsl:value-of select="Name"/>
        <xsl:value-of select="$delimeter"/>

        <xsl:value-of select="Address"/>
        <xsl:value-of select="$delimeter"/>

        <xsl:value-of select="Phone"/>
        <xsl:value-of select="$newline"/>
    </xsl:template>

    <xsl:template match="entry/Dependents">
        <xsl:call-template name="valueOrParentOrNone">
            <xsl:with-param name="fieldValue" select="Name"/>
        </xsl:call-template>
        <xsl:value-of select="$delimeter"/>

        <xsl:call-template name="valueOrParentOrNone">
            <xsl:with-param name="fieldValue" select="Address"/>
        </xsl:call-template>
        <xsl:value-of select="$delimeter"/>

        <xsl:call-template name="valueOrParentOrNone">
            <xsl:with-param name="fieldValue" select="Phone"/>
        </xsl:call-template>
        <xsl:value-of select="$newline"/>

    </xsl:template>


    <xsl:template name="valueOrParentOrNone">
        <xsl:param name="fieldValue"/>
        <xsl:choose>
            <!-- Use passed in node if exists -->
            <xsl:when test="$fieldValue">
                <xsl:value-of select="$fieldValue" />
            </xsl:when>
            <!-- Use parent node of the same name if exists -->
            <xsl:when test="../$fieldName">
                <xsl:value-of select="../$fieldName" />
            </xsl:when>
            <!-- Use "None" -->
            <xsl:otherwise>
                <xsl:text>"None"</xsl:text>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

</xsl:stylesheet>

Original input XML:

<root>
    <entry>
        <Name>J. Smith</Name>
        <Address>1123 XML Lane</Address>
        <Phone>123-456-7890</Phone>
        <Dependents>
            <Name>S. Smith</Name>
            <Address>1123 XML Lane</Address>
            <Phone>123-456-0987</Phone>
        </Dependents>
    </entry>
    <entry>
        <Name>L. Hines</Name>
        <Address>423 Programming Way</Address>
        <Dependents>
            <Name>P. Hines</Name>
        </Dependents>
    </entry>
</root>

New Input XML

<root>
    <entry>
        <Name>J. Smith</Name>
        <Address>1123 XML Lane</Address>
        <Phone>123-456-7890</Phone>
        <DependentName>S. Smith</DependentName>
        <DependentAddress>1123 XML Lane</DependentAddress>
        <DependentPhone>123-456-0987</DependentPhone>
    </entry>
    <entry>
        <Name>L. Hines</Name>
        <Address>423 Programming Way</Address>
        <DependentName>P. Hines</DependentName>
    </entry>
</root>

You'll notice that not all of the values are available in either format above. I need to reuse the parent values when the dependent value doesn't exist. If neither exists, I need to use the value of "None". Input format changed so that the Dependents sibling no longer exists. Instead, the children of the Dependents has been raised to be siblings to the regular person values and are now a direct child of entry.

Intended output.

"J. Smith","1123 XML Lane","123-456-7890"
"S. Smith","1123 XML Lane","123-456-0987"
"L. Hines","423 Programming Way",,
"P. Hines","423 Programming Way","None"

EDIT: Sorry for being confusing.

Upvotes: 0

Views: 1189

Answers (3)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243469

Here is a complete transformation:

<xsl:stylesheet version="2.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:f="my:f">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="entry">
   <xsl:value-of select="string-join(
      (string(Name), string(Address), string(Phone), ''[not(current()/Phone)]),
       ','), 
      '&#xA;'"/>
   <xsl:apply-templates select="." mode="dependent"/>
 </xsl:template>

 <xsl:template match="entry" mode="dependent">
   <xsl:value-of select="string-join(
     (f:getValue(.,Name, DependentName), f:getValue(.,Address, DependentAddress), 
      f:getValue(.,Phone, DependentPhone)),','), 
      '&#xA;'"/>
 </xsl:template>

 <xsl:function name="f:getValue">
   <xsl:param name="pParent" as="element()"/>
   <xsl:param name="pChild" as="xs:string?"/>
   <xsl:param name="pdepChild" as="xs:string?"/>

   <xsl:variable name="vUsethis" select="($pdepChild, $pChild)[1]"/>

   <xsl:sequence select="($vUsethis[.],'None')[1]"/>
 </xsl:function>
</xsl:stylesheet>

When this transformation is applied on the provided XML document:

<root>
    <entry>
        <Name>J. Smith</Name>
        <Address>1123 XML Lane</Address>
        <Phone>123-456-7890</Phone>
        <DependentName>S. Smith</DependentName>
        <DependentAddress>1123 XML Lane</DependentAddress>
        <DependentPhone>123-456-0987</DependentPhone>
    </entry>
    <entry>
        <Name>L. Hines</Name>
        <Address>423 Programming Way</Address>
        <DependentName>P. Hines</DependentName>
    </entry>
</root>

the wanted, correct result is produced:

J. Smith,1123 XML Lane,123-456-7890 
S. Smith,1123 XML Lane,123-456-0987 
L. Hines,423 Programming Way,, 
P. Hines,423 Programming Way,None 

Upvotes: 1

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243469

Just use:

  <xsl:sequence select="($fieldValue[.], replace($fieldValue, 'Dependent', ''),'None')[1]"/>

Upvotes: 1

michael.hor257k
michael.hor257k

Reputation: 116982

IMHO, your best bet would be to rewrite your template as:

<xsl:template name="valueOrAltOrNone">
    <xsl:param name="field"/>
    <xsl:param name="alt-field"/>
    <xsl:choose>
        <xsl:when test="$field">
            <xsl:value-of select="$field" />
        </xsl:when>
        <xsl:when test="$alt-field">
            <xsl:value-of select="$alt-field" />
        </xsl:when>
        <xsl:otherwise>
            <xsl:text>"None"</xsl:text>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

and call it as (for example):

<xsl:call-template name="valueOrAltOrNone">
    <xsl:with-param name="field" select="DependentName"/>
    <xsl:with-param name="alt-field" select="Name"/>
</xsl:call-template>

There is probably a shorter solution to do same, but I wanted to minimize the required changes.

Upvotes: 1

Related Questions