string replace using XSLT

I have my xml as

<root>

<case id=1>
<child>
<action querystring="p1=test;p2=test1" id=1 name="blah" />
<action querystring="p1=#clue1#;p2=test1" id=2 name="blah" />
</child>
</case>

</root>

if query string contains something like that as in action with id=2

querystring="p1=#Pass1:clue1#;p2=test1" id=2 name="blah"

so #clue1" is actually in other file

which looks like

<root>

<region id="pass1">
<parameter id="clue1" value="test" />
</region>

</root>

so i have to replave pass1:clue1 with test.

thanks




LVL 15
praneethaAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Geert BormansInformation ArchitectCommented:
Hi praneetha,

just to be sure, I give you the input files I used (normalised)

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <case id="1">
        <child>
        <action querystring="p1=test;p2=test1" id="1" name="blah" />
            <action querystring="p1=#pass1:clue1#;p2=test1" id="2" name="blah" />
        </child>
    </case>
</root>

region.xml
-----------
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <region id="pass1">
        <parameter id="clue1" value="test" />
    </region>
</root>

this XSLT does what I think you want

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="node()">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
   
    <xsl:template match="action">
        <xsl:copy>
            <xsl:copy-of select="@*[not(name() = 'querystring')]"/>
            <xsl:choose>
                <xsl:when test="contains(@querystring, '#')">
                    <xsl:variable name="pre" select="substring-before(@querystring, '#')"/>
                    <xsl:variable name="post" select="substring-after(substring-after(@querystring, '#'), '#')"/>
                    <xsl:variable name="replace" select="substring-before(substring-after(@querystring, '#'), '#')"/>
                    <xsl:variable name="arg1" select="substring-before($replace, ':')"/>
                    <xsl:variable name="arg2" select="substring-after($replace, ':')"/>
                    <xsl:attribute name="querystring">
                        <xsl:value-of select="$pre"/>
                        <xsl:value-of select="document('region.xml')//region[@id=$arg1]/parameter[@id=$arg2]/@value"/>
                        <xsl:value-of select="$post"/>
                    </xsl:attribute>
                </xsl:when>
                <xsl:otherwise><xsl:copy-of select="@querystring"/></xsl:otherwise>
            </xsl:choose>
           
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
 </xsl:stylesheet>


Cheers!
0
Geert BormansInformation ArchitectCommented:
praneetha,

the template rule for node()
simply does an identity copy
this works for all elements except for the action element, which has its more specific template

for action I copy all the attributes except 'querystring'

if @querystring doesn't contain a '#' I also copy it

otherwise, I take the thing between the # and the #
split it based on the ':' and do a lookup in the other document

If you need a somewhat different logic, I will be happy to help

cheers

Geert
0
praneethaAuthor Commented:
thanks. will try it and let you know.
0
Introducing Cloud Class® training courses

Tech changes fast. You can learn faster. That’s why we’re bringing professional training courses to Experts Exchange. With a subscription, you can access all the Cloud Class® courses to expand your education, prep for certifications, and get top-notch instructions.

praneethaAuthor Commented:
i think its working fine but fialing in cases where querystring can contain more than one #

like below

    <action querystring="p1=#pass1:clue1#;p2=#Pass2:Clue9#" id="2" name="blah" />

it works for pass1:clue1 and doesnt do pass2:clue9

i shoudl have mentioned this to you before.

me trying to fix it so that i cna learn too.

what does it mean when its precded by @ like @queryString. is it the real attribute from XML?

thanks for your help
0
Geert BormansInformation ArchitectCommented:
well, if you need to make multiple replacements of #....# sequences,
you need recursive processing of the attribute

I will develop an example in a minute...
you will see it is a bit more complex

@queryString indeed means the XML attribute queryString
0
Geert BormansInformation ArchitectCommented:
here is the XML I use

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <case id="1">
        <child>
        <action querystring="p1=test;p2=test1" id="1" name="blah" />
            <action querystring="p1=#pass1:clue1#;p2=#pass2:clue9#"  id="2" name="blah" />
        </child>
    </case>
</root>

NOTE that I lowercased the attributes in my example, it is all case sensitive, so make sure it is correct

this is region.xml
--------------------
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <region id="pass1">
        <parameter id="clue1" value="test" />
    </region>
    <region id="pass2">
        <parameter id="clue9" value="test5" />
    </region>
</root>

and here is the XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="node()">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
   
    <xsl:template match="action">
        <xsl:copy>
            <xsl:copy-of select="@*[not(name() = 'querystring')]"/>
            <xsl:choose>
                <xsl:when test="contains(@querystring, '#')">
                    <xsl:attribute name="querystring">
                        <xsl:call-template name="processQS">
                            <xsl:with-param name="qs" select="@querystring"/>
                        </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="processQS">
        <xsl:param name="qs"/>
        <xsl:if test="substring-before($qs, '#')">
            <xsl:value-of select="substring-before($qs, '#')"/>
        </xsl:if>
        <xsl:call-template name="processQueryPair">
            <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="processQS">
                    <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="processQueryPair">
        <xsl:param name="qp"/>
        <xsl:param name="arg1" select="substring-before($qp, ':')"></xsl:param>
        <xsl:param name="arg2" select="substring-after($qp, ':')"></xsl:param>
        <xsl:value-of select="document('region.xml')//region[@id=$arg1]/parameter[@id=$arg2]/@value"/>
    </xsl:template>
   
</xsl:stylesheet>
0
Geert BormansInformation ArchitectCommented:
named templates are a bit like functions
and as explained in your previous question, you can pass parameters

processQS progressively eats up the querystring attribute
and copies string parts outside #...# sequences to the output
and calls the template processQueryPair with the sequence inside a #..# as a parameter

note that processQS is setup as a recursive function
that is the only way to make the variables change in XSLT

have a close look at the code and let me know if you don't get it entirely

cheers
0
praneethaAuthor Commented:
when exactly is the replace happening.

ok processQueryPair takes what is between # and # and splits with : and gets the value attribute from region.xml.

so its gets the value but when is the replace happening...

1. <xsl:template name="processQS">
  2.     <xsl:param name="qs"/>
    3.    <xsl:if test="substring-before($qs, '#')">
      4.      <xsl:value-of select="substring-before($qs, '#')"/>

i guess we r doing this to get everything before first #

       5. </xsl:if>
       6. <xsl:call-template name="processQueryPair">
         7.   <xsl:with-param name="qp" select="substring-before(substring-after($qs, '#') , '#')"/>
        8.</xsl:call-template>
and here we get the date from region.xml but dont know where we r replacing it

        9.<xsl:choose>
and we r checking again if it has more #

          10.  <xsl:when test="contains(substring-after(substring-after($qs, '#') , '#'), '#')">
             11.   <xsl:call-template name="processQS">
                12.    <xsl:with-param name="qs" select="substring-after(substring-after($qs, '#') , '#')"/>
                13. </xsl:call-template>
            14. </xsl:when>
            15. <xsl:otherwise><xsl:value-of select="substring-after(substring-after($qs, '#') , '#')"/></xsl:otherwise>
        16. </xsl:choose>
       
     17. </xsl:template>

may be u can briefly explain each line..it would help me great deal..:( sorry for the trouble

thanks
0
Geert BormansInformation ArchitectCommented:
no problem

I first continue the numbering
18.   <xsl:template name="processQueryPair">
19.        <xsl:param name="qp"/>
20.        <xsl:param name="arg1" select="substring-before($qp, ':')"></xsl:param>
21.        <xsl:param name="arg2" select="substring-after($qp, ':')"></xsl:param>
22.        <xsl:value-of select="document('region.xml')//region[@id=$arg1]/parameter[@id=$arg2]/@value"/>
23.    </xsl:template>


1. starts the named template "processQS", think of it like a function
2. binds the local parameter "qs" to the parameter passed in using xsl:with-param
3. tests to see there is a part before the first #
4. if there is a part before the first #, it is outputted
between lines: your observation is correct
5. closes the if statement. I do the test here, for the condition that # is the first character, then line 4 would be an issue
6. I call the template processQueryPair (to process the part between the first and second #)
7. construction of the parameter, part after the first # and before the second
8. close calling named template
between lines: the replacing happens in the template processQueryPair, where I have the arguments... line 22.
9. start of a choose, in order to proces the remainder, if there is another #
between lines: your observation is correct
10. test: is there a # left in the remainder, if there is...
11. ... recursively call the processQS template, but with a smaller parameter
...
15 if there is no # in the remainder, just output it

18.   start of template (function) processQueryPair, here the actual querystring is replaced
19.        parameter binding
20.        variable arg1 is the part before the ":"
21.        variable arg2is the part after the ":"
22.        lookup in the other file

hope this helps
cheers
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
praneethaAuthor Commented:
thank you so much

i definitely learnt some XSLT thanks to you. :)
0
Geert BormansInformation ArchitectCommented:
welcome
0
praneethaAuthor Commented:
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
XML

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.