Link to home
Start Free TrialLog in
Avatar of praneetha
praneetha

asked on

xsl accessing parent attribute

my inout xml contains
 <Page id="MenuEdit" Title="File Item Names List">
<Control id="UndoMenuEdit" value="title=Manager&amp;&amp;winformid=&amp;&amp;parent=Edit&amp;&amp;name=Undo"></Control>
...
...
</Page>
and i wrote an xsl to change it too

 <Page id="MenuEdit" Title="File Item Names List">
<Control id="UndoMenuEdit" value="title=Manager&amp;&amp;winformid=&amp;&amp;parent=Edit&amp;&amp;name=Undo"></Control>
    <Control>
<control id="UndoMenuEdit_title" value="Manager"></control>
<control id="UndoMenuEdit_winformid" value=""></control>
<control id="UndoMenuEdit_parent" value="Edit"></control>
<control id="UndoMenuEdit_name" value="Undo"></control>
</Control>
    </Page>
and in addition to this i want to add a new attribute to Control called newvalue and i want it to contain
newvalue="title=#MenuEdit:UndoMenuEdit_title#&amp;&amp;winformid=#MenuEdit:UndoMenuEdit_winformid#&amp;&amp;parent=#MenuEdit:UndoMenuEdit_parent#&amp;&amp;name=#MenuEdit:UndoMenuEdit_name#"

so the output xml should now contain

 <Page id="MenuEdit" Title="File Item Names List">
<Control id="UndoMenuEdit" value="title=Manager&amp;&amp;winformid=&amp;&amp;parent=Edit&amp;&amp;name=Undo" newvalue="title=#MenuEdit:UndoMenuEdit_title#&amp;&amp;winformid=#MenuEdit:UndoMenuEdit_winformid#&amp;&amp;parent=#MenuEdit:UndoMenuEdit_parent#&amp;&amp;name=#MenuEdit:UndoMenuEdit_name#"></Control>
    <Control>
<control id="UndoMenuEdit_title" value="Manager"></control>
<control id="UndoMenuEdit_winformid" value=""></control>
<control id="UndoMenuEdit_parent" value="Edit"></control>
<control id="UndoMenuEdit_name" value="Undo"></control>
</Control>
    </Page>
 
can some one please help me with it
Avatar of Gertone (Geert Bormans)
Gertone (Geert Bormans)
Flag of Belgium image

you can simply use
<xsl:attribute name="newvalue">title=#MenuEdit:UndoMenuEdit_title#&amp;&amp;winformid=#MenuEdit:UndoMenuEdit_winformid#&amp;&amp;parent=#MenuEdit:UndoMenuEdit_parent#&amp;&amp;name=#MenuEdit:UndoMenuEdit_name#</xsl:attribute>

make sure you put this xsl:attribute immedeatly after the opening start tag of your Content element,
surely before you write any content to it
if you use <xsl:copy> put it behind the <xsl:copy> tag
if you use <xsl:copy-of>... you need to rewrite that to using <xsl:copy>

cheers

Geert
Avatar of praneetha
praneetha

ASKER

well its not always the same thing.

ok here is the xsl may be this will explain betteR: let me know if u need more info: well i have to know to know how to remember the new ids created. i dont mind writing an other xsl to do it. may be that would be easier instead of modifying the existing one.

 <xsl:template match="node()">
    <xsl:value-of select="$newline"/>
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <xsl:value-of select="$newline"/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>
 
  <xsl:template match="Control">
    <xsl:value-of select="$newline"/>
    <xsl:copy>
      <xsl:variable name="id" select="@id" />
      <xsl:copy-of select="@*[not(name() = 'queryString')]"/>
      <xsl:choose>
        <xsl:when test="contains(@value, '=')">
          <xsl:attribute name="queryString">
            <xsl:call-template name="processValue">
              <xsl:with-param name="qs" select="@value"/>
            </xsl:call-template>
          </xsl:attribute>
        </xsl:when>
        <xsl:otherwise>
          <xsl:copy-of select="@queryString"/>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>
 
 
  <xsl:template name="processValue">
    <xsl:param name="qs"/>

   
    <xsl:call-template name="ProcessQual">
      <xsl:with-param name="qp" select="substring-before(substring-after($qs, '=') , '=')"/>
    </xsl:call-template>
   
    <xsl:choose>
      <xsl:when test="contains(substring-after(substring-after($qs, '') , '#'), '#')">
        <xsl:call-template name="processValue">
          <xsl:with-param name="qs" select="substring-after(substring-after($qs, '#') , '#')"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="substring-after(substring-after($qs, '#') , '#')"/>
      </xsl:otherwise>
    </xsl:choose>
   
  </xsl:template>
 
 
  <xsl:template name="ProcessQual">
    <xsl:param name="qs1"/>
    <xsl:param name="arg1" select="substring-before($qs1, '=')"></xsl:param>
    <xsl:param name="arg2" select="substring-after($qs1, '=')"></xsl:param>
    <control>
      <xsl:attribute name="id">
      <xsl:value-of select="$id"/>_<xsl:value-of select="$arg1"/>
      </xsl:attribute>
      <xsl:attribute name="value">
        <xsl:value-of select="$arg2"/>
      </xsl:attribute>              
    </control>
  </xsl:template>
I am not really sure what you want
- it seems that you want to access the $id defined in
 <xsl:template match="Control">
    <xsl:value-of select="$newline"/>
    <xsl:copy>
      <xsl:variable name="id" select="@id" />
in the named template ProcessQual
why don't you pass it, like this

<xsl:template match="Control">
    <xsl:value-of select="$newline"/>
    <xsl:copy>
      <xsl:variable name="id" select="@id" />
      <xsl:copy-of select="@*[not(name() = 'queryString')]"/>
      <xsl:choose>
        <xsl:when test="contains(@value, '=')">
          <xsl:attribute name="queryString">
            <xsl:call-template name="processValue">
              <xsl:with-param name="qs" select="@value"/>
              <xsl:with-param name="id" select="@id"/>
            </xsl:call-template>
          </xsl:attribute>

pass it from ProcessVal to    

 <xsl:template name="processValue">
    <xsl:param name="qs"/>
    <xsl:param name="id"/>
    <xsl:call-template name="ProcessQual">
      <xsl:with-param name="qp" select="substring-before(substring-after($qs, '=') , '=')"/>
      <xsl:with-param name="id" select="$id"/>
    </xsl:call-template>

and you can use it where you want to use it now

- note that you can easily query the attribute id of a parent element
using ../@id
remember there are quite a number of axes, your XSLT processor can follow

cheers

well no let me explain to you again

my input xml looks like

<control id="id1" value="param1_1=value1&&param2_1=value2&&param3_1=value3">
<control id="id2" value="param1_2=value1&&param2_2=value2&&param3_2=value3">
<control id="id3" value="param1_3=value1">

now my aim is to remove value containing hard coded value. so i wrote above xsl to convert this xml into other xml which looks like this

<control id="id1" value="param1_1=value1&&param2_1=value2&&param3_1=value3">

<control id="id1_param1_1" value="value1" />
<control id="id1_param2_1" value="value2" />
<control id="id1_param3_1" value="value3" />

<control id="id2" value="param1_2=value1&&param2_2=value2&&param3_2=value3">

<control id="id2_param1_2" value="value1" />
<control id="id2_param2_2" value="value2" />


<control id="id3" value="param1_3=value1">

<control id="id3_param1_3" value="value1" />

and all the controls whose value attribute contains param=value string...and since that value is made into other element i want it to cntain new attribute called "newvalue". so my final output would be like below

<control id="id1" value="param1_1=value1&&param2_1=value2&&param3_1=value3" newvalue="param1_1=#id1_param1_1#&&param2_1=#id1_param2_1#&&param3_1=#id1_param3_1#">

<control id="id1_param1_1" value="value1" />
<control id="id1_param2_1" value="value2" />
<control id="id1_param3_1" value="value3" />

<control id="id2" value="param1_2=value1&&param2_2=value2&&param3_2=value3" newvalue="param1_1=#id2_param1_2#&&param2_1=#id2_param2_2#">

<control id="id2_param1_2" value="value1" />
<control id="id2_param2_2" value="value2" />


<control id="id3" value="param1_3=value1" newvalue="param1_3=#id3_param1_3#">

<control id="id3_param1_3" value="value1" />

so in other words. if value attribute of control is jsut *** string its good. or it should be param=#id of other control#

i am sorry for the confusion so apart from creating this new control elements i want to create new attribute with modified param list


let me know if its still not clear
praneetha,

This should do what you want,
except that you have a && too many at the end of each attribute

I will solve that later today and will give some explanation then too

cheers

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes" method="xml"/>
    <xsl:template match="controls">
        <controls>
            <xsl:apply-templates/>
        </controls>
    </xsl:template>
   
    <xsl:template match="control">
        <control>
            <xsl:copy-of select="@*"/>
            <xsl:attribute name="newvalue">
                <xsl:call-template name="processValue">
                    <xsl:with-param name="strVal" select="concat(@value, '&amp;&amp;')"/>
                    <xsl:with-param name="curID" select="@id"/>
                    <xsl:with-param name="curMod" select="attribute"/>
                </xsl:call-template>
            </xsl:attribute>
        </control>
        <xsl:call-template name="processValue">
            <xsl:with-param name="strVal" select="concat(@value, '&amp;&amp;')"/>
            <xsl:with-param name="curID" select="@id"/>
            <xsl:with-param name="curMod" select="'element'"/>
        </xsl:call-template>
    </xsl:template>
   
    <xsl:template name="processValue">
        <xsl:param name="strVal"/>
        <xsl:param name="curID"/>
        <xsl:param name="curMod"/>
            <xsl:if test="contains($strVal, '&amp;&amp;')">
                <xsl:choose>
                    <xsl:when test="$curMod = 'element'">
                        <xsl:call-template name="processPair">
                            <xsl:with-param name="strPair" select="substring-before($strVal, '&amp;&amp;')"/>
                            <xsl:with-param name="curID" select="$curID"/>
                        </xsl:call-template>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:call-template name="processPairAttribute">
                            <xsl:with-param name="strPair" select="substring-before($strVal, '&amp;&amp;')"/>
                            <xsl:with-param name="curID" select="$curID"/>
                        </xsl:call-template>
                    </xsl:otherwise>
                </xsl:choose>
               
            </xsl:if>
            <xsl:if test="string-length(substring-after($strVal, '&amp;&amp;')) &gt; 0">
                <xsl:call-template name="processValue">
                    <xsl:with-param name="strVal" select="substring-after($strVal, '&amp;&amp;')"/>
                    <xsl:with-param name="curID" select="$curID"/>
                    <xsl:with-param name="curMod" select="$curMod"/>
                </xsl:call-template>
            </xsl:if>
    </xsl:template>
   
    <xsl:template name="processPair">
        <xsl:param name="strPair"/>
        <xsl:param name="curID"/>
        <xsl:if test="contains($strPair, '=')">
            <control>
                <xsl:attribute name="id"><xsl:value-of select="concat($curID, '_' , substring-before($strPair, '='))"/></xsl:attribute>
                <xsl:attribute name="value"><xsl:value-of select="substring-after($strPair, '=')"/></xsl:attribute>
            </control>
        </xsl:if>
    </xsl:template>

    <xsl:template name="processPairAttribute">
        <xsl:param name="strPair"/>
        <xsl:param name="curID"/>
        <xsl:if test="contains($strPair, '=')">
               <xsl:value-of select="concat($curID, '_' , substring-before($strPair, '='))"/>
            <xsl:text>=#</xsl:text>
                <xsl:value-of select="substring-after($strPair, '=')"/>
            <xsl:text>#</xsl:text>
            <xsl:text>&amp;&amp;</xsl:text>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

open for comments
thank u that works

i just changed processPairAttribute to following since i just wanted it diffrently...i just was trying to get rid of those extra &amp;&amp; at the end. hmm some how couldnt get it to work....is the @newvalue length always 0 inside this template. i thought it wouldnt be.

anyways thank u so much for your help. i really appreciate it. i am gonna keep trying to get rid of these &amp;&amp;...

thanks again :)

<xsl:template name="processPairAttribute">
    <xsl:param name="strPair"/>
    <xsl:param name="curID"/>
    <xsl:if test="contains($strPair, '=')">
      <!--<xsl:choose>
      --><!--<xsl:when test="string-length(//Page/Control[@id=$curID]/@newvalue)=0">
        <xsl:text>&amp;&amp;</xsl:text>
      </xsl:when>
        <xsl:otherwise>
          <xsl:text>&amp;&amp;</xsl:text>
        </xsl:otherwise>--><!--
        </xsl:choose>-->
      <!--<xsl:value-of select="concat($curID, '_' , substring-before($strPair, '='))"/>-->
      <xsl:value-of select="substring-before($strPair, '=')"/>
      <!--<xsl:value-of select="$curID"/>-->
      <xsl:text>=#</xsl:text>
      <!--<xsl:value-of select="substring-after($strPair, '=')"/>-->
      <xsl:value-of select="../@id"/>:<xsl:value-of select="concat($curID, '_' , substring-before($strPair, '='))"/>  
      <xsl:text>#</xsl:text>
      <xsl:text>&amp;&amp;</xsl:text>
    </xsl:if>
  </xsl:template>
ASKER CERTIFIED SOLUTION
Avatar of Gertone (Geert Bormans)
Gertone (Geert Bormans)
Flag of Belgium image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
:) cool that works

thank u so much.

i actually did not try to understand the XSL you wrote yet. i will do it asap. and close the question or may be bother u little bit more :)

thank u so much
you are welcome

> i actually did not try to understand the XSL you wrote yet

For me it is important that eventually you understand this (and maybe learn something)
so don't hesitate asking questions

basically here is what I do

the core logic is in this template

  <xsl:template match="control">
        <control>
            <xsl:copy-of select="@*"/>
=> here I just copied all the attributes
            <xsl:attribute name="newvalue">
=> a newvalue attribute is created
                <xsl:call-template name="processValue">
                    <xsl:with-param name="strVal" select="concat(@value, '&amp;&amp;')"/>
                    <xsl:with-param name="curID" select="@id"/>
                    <xsl:with-param name="curMod" select="attribute"/>
=> for the content of this attribute I make a call to processValue
=> I need the content of the attribute value as a parameter, I concat with && to make my tests in the sequel simpler
=> I pass the attribute id because I need it to construct new values
=> and I pass a stateVariable to know later whether the call is made for the attribute or for the element (in order to call processPair or processPairAttribute)
=> this named template will be called recursively until the entire string is processed
                </xsl:call-template>
            </xsl:attribute>
        </control>
        <xsl:call-template name="processValue">
=> here I call the same template again, to construct the new control elements
            <xsl:with-param name="strVal" select="concat(@value, '&amp;&amp;')"/>
            <xsl:with-param name="curID" select="@id"/>
            <xsl:with-param name="curMod" select="'element'"/>
        </xsl:call-template>
    </xsl:template>

the named templates do the construction of the attribute string and the control elements
there is the real trick... instead of trying to access the parents new attribute... I process the string content twice to construct the newvalue attribute value
and the control elements... in a similar fashion

take your time to look through the code, and don't hessitate to ask for clarifications

cheers

Geert