?
Solved

xsl accessing parent attribute

Posted on 2006-04-26
12
Medium Priority
?
513 Views
Last Modified: 2013-11-19
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
0
Comment
Question by:praneetha
  • 5
  • 5
10 Comments
 
LVL 60

Expert Comment

by:Geert Bormans
ID: 16547510
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
0
 
LVL 15

Author Comment

by:praneetha
ID: 16548367
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>
0
 
LVL 60

Expert Comment

by:Geert Bormans
ID: 16548563
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

0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 15

Author Comment

by:praneetha
ID: 16548812
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


0
 
LVL 15

Author Comment

by:praneetha
ID: 16548813
let me know if its still not clear
0
 
LVL 60

Expert Comment

by:Geert Bormans
ID: 16551496
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
0
 
LVL 15

Author Comment

by:praneetha
ID: 16555098
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>
0
 
LVL 60

Accepted Solution

by:
Geert Bormans earned 2000 total points
ID: 16556829
Hi,

Here is an easy way to add the && in the correct places
move it from the processPairAttribute template in the processValue template
(changes made with =>)

            <xsl:if test="string-length(substring-after($strVal, '&amp;&amp;')) &gt; 0">
=>                <xsl:if test="not($curMod = 'element')"><xsl:text>&amp;&amp;</xsl:text></xsl:if>
                <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="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:if>
    </xsl:template>
</xsl:stylesheet>

cheers

Geert
0
 
LVL 15

Author Comment

by:praneetha
ID: 16563488
:) 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
0
 
LVL 60

Expert Comment

by:Geert Bormans
ID: 16568195
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
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

I was working on a PowerPoint add-in the other day and a client asked me "can you implement a feature which processes a chart when it's pasted into a slide from another deck?". It got me wondering how to hook into built-in ribbon events in Office.
Have you tried to learn about Unicode, UTF-8, and multibyte text encoding and all the articles are just too "academic" or too technical? This article aims to make the whole topic easy for just about anyone to understand.
Viewers will learn about arithmetic and Boolean expressions in Java and the logical operators used to create Boolean expressions. We will cover the symbols used for arithmetic expressions and define each logical operator and how to use them in Boole…
Learn how to create flexible layouts using relative units in CSS.  New relative units added in CSS3 include vw(viewports width), vh(viewports height), vmin(minimum of viewports height and width), and vmax (maximum of viewports height and width).
Suggested Courses

839 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question