XSLT - Transform xml to xml

Hello,

I'm new to using XML and XSLT. I am trying to convert one xml doc into another one, so that just the relevant information is available.

Please see the attached code. Please help me with the code.

Thanks.
FROM VERSION
------------

<RGRS VER="3.2">
        <PARAM name="q" value="rome" original_value="rome"/>
        <RES SN="1" EN="10">
                <R N="1">
                        <MT N="TITLE" V="La Pergola, Rome"/>
                        <MT N="THEME" V="Chef, Fast, Healthy"/>
				   <MT N="AUTHOR1" V="Emily Ruben"/>
				   <MT N="AUTHOR2" V="Stephen King"/>
                </R>
                <R N="2">
                        <MT N="TITLE" V="Metro Cafe"/>
                        <MT N="THEME" V="Make Ahead"/>
                </R>
        </RES>
</RGRS>


TO VERSION
----------

<?xml version="1.0"?>
<catalog>
   <books>
      <book>
         <title>La Pergola, Rome</title>
         <themes>
		  <theme>
			<name>Chef</name>
		  </theme>
		  <theme>
			<name>Fast</name>
		  </theme>
		  <theme>
			<name>Healthy</name>
		  </theme>
         </themes>
         <authors>
		  <author>
			<name>Emily Ruben</name>
		  </author>
		  <author>
			<name>Stephen King</name>
		  </author>
         </authors>
      </book>
      <book id="bk102">
         <title>Metro Cafe</title>
         <themes>
		  <theme>
			<name>Make Ahead</name>
		  </theme>
         </themes>
      </book>
   </books>
</catalog>

Open in new window

sunseshasaiAsked:
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:
Since you are learning, I suggest that you start using XSLT2 from the very start.
You can do so by using Saxon
The solution I provide uses one XSLT2 construct, the  "tokenize()"
If you need to bring that back to XSLT1, you will need some recursive programming,
let me know if that is the case

The stylesheet is really straightforward. You will figure out how it works, good luck
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"></xsl:output>
    <xsl:template match="RGRS">
        <catalog>
            <xsl:apply-templates select="RES"/>
        </catalog>
    </xsl:template>
    <xsl:template match="RES">
        <books>
            <xsl:apply-templates select="R"/>
        </books>
    </xsl:template>
    <xsl:template match="R">
        <book>
            <title>
                <xsl:value-of select="MT[@N = 'TITLE']/@V"/>
            </title>
            <themes>
                <xsl:for-each select="tokenize(MT[@N = 'THEME']/@V, ',')">
                    <theme>
                        <name><xsl:value-of select="normalize-space(.)"/></name>
                    </theme>
                </xsl:for-each>
            </themes>
            <xsl:if test="MT[starts-with(@N, 'AUTHOR')]">
                <authors>
                    <xsl:apply-templates select="MT[starts-with(@N, 'AUTHOR')]"/>
                </authors>
            </xsl:if>
        </book>
    </xsl:template>
    <xsl:template match="MT[starts-with(@N, 'AUTHOR')]">
        <author>
            <name>
                <xsl:value-of select="@V"/>
            </name>
         </author>
    </xsl:template>
</xsl:stylesheet>

Open in new window

0
sunseshasaiAuthor Commented:
Hello Gertone,

Thanks for sending the code. I am getting the following errors

Error 1:     No character data is allowed between top-level elements

    <xsl:template match="MT[starts-with(@N, 'AUTHOR')]">
        <author>
            <name>
                <xsl:value-of select="@V"/>
            </name>
         </author>
    </xsl:template>

Error 2: Error in expression tokenize(MT[@N = 'THEME']/@V, ','): Unknown system function: tokenize

            <themes>
                <xsl:for-each select="tokenize(MT[@N = 'THEME']/@V, ',')">
                    <theme>
                        <name><xsl:value-of select="normalize-space(.)"/></name>
                    </theme>
                </xsl:for-each>
            </themes>

Please help. Thanks.
0
Geert BormansInformation ArchitectCommented:
Which processor are you using?
If it doesn't matter to you, I recommend that you use saxon9.2HE (check on sourceforge or on www.saxonica.com)
then this will not happen. As I said this is an XSLT2 stylesheet and can not be processed using an XSLT1 processor
So, explain to me how you want to run the XSLT process

If you can't run an XSLT2 process, then I will change your stylesheet into an XSLT1 stylesheet

I don't understand error1 actualy, there is no data at places it should not be, maybe a bad paste?
0
Cloud Class® Course: MCSA MCSE Windows Server 2012

This course teaches how to install and configure Windows Server 2012 R2.  It is the first step on your path to becoming a Microsoft Certified Solutions Expert (MCSE).

Geert BormansInformation ArchitectCommented:
So, here is the XSLT1 version of the stylesheet
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"></xsl:output>
    <xsl:template match="RGRS">
        <catalog>
            <xsl:apply-templates select="RES"/>
        </catalog>
    </xsl:template>
    <xsl:template match="RES">
        <books>
            <xsl:apply-templates select="R"/>
        </books>
    </xsl:template>
    <xsl:template match="R">
        <book>
            <title>
                <xsl:value-of select="MT[@N = 'TITLE']/@V"/>
            </title>
            <xsl:if test="MT[@N = 'THEME']/@V">
                <themes>
                    <xsl:call-template name="process-themes">
                        <xsl:with-param name="str" select="MT[@N = 'THEME']/@V"/>
                    </xsl:call-template>
                </themes>
            </xsl:if>
            <xsl:if test="MT[starts-with(@N, 'AUTHOR')]">
                <authors>
                    <xsl:apply-templates select="MT[starts-with(@N, 'AUTHOR')]"/>
                </authors>
            </xsl:if>
        </book>
    </xsl:template>
    <xsl:template match="MT[starts-with(@N, 'AUTHOR')]">
        <author>
            <name>
                <xsl:value-of select="@V"/>
            </name>
         </author>
    </xsl:template>
    <xsl:template name="process-themes">
        <xsl:param name="str"/>
        <xsl:choose>
            <xsl:when test="not(contains($str, ','))">
                <theme>
                    <name><xsl:value-of select="normalize-space($str)"/></name>
                </theme>
            </xsl:when>
            <xsl:otherwise>
                <theme>
                    <name><xsl:value-of select="normalize-space(substring-before($str, ','))"/></name>
                </theme>
                <xsl:call-template name="process-themes">
                    <xsl:with-param name="str" select="substring-after($str, ',')"/>
                </xsl:call-template>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

Open in new window

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
sunseshasaiAuthor Commented:
Hello Gertone,
The solution provided by you, worked well for me. Thanks.
The reason for error 1 is, the blank spaces/tabs in the code. Once I removed them it worked for me.
Thanks again.
0
Geert BormansInformation ArchitectCommented:
welcome
0
sunseshasaiAuthor Commented:
Hi Gertone,
The solution worked great for me. Only one change needed.

if themes has data we are converting as
         <themes>
            <theme>
               <name>Chef</name>
            </theme>
            <theme>
               <name>Fast</name>
            </theme>
         </themes>

if it's empty it's showing as
         <themes>
            <theme>
               <name/>
            </theme>
         </themes>


If it's empty, Is it possible to change it to
         <themes />

And the same kind of change we need it for <authors> too.
<authors />

Please help. Thanks.
0
Geert BormansInformation ArchitectCommented:
I have apparently answered this in your follow up question.
The code for disgarding themes was there for elements that were not present,
I now extended that code for elements that have the right attributes, but have empty attribute values
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
Web Languages and Standards

From novice to tech pro — start learning today.