Wrox Programmer Forums

Need to download code?

View our list of code downloads.

Go Back   Wrox Programmer Forums > XML > XSLT
Password Reminder
Register
| FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of tens of thousands of software programmers and website developers including Wrox book authors and readers. As a guest, you can read any forum posting. By joining today you can post your own programming questions, respond to other developers’ questions, and eliminate the ads that are displayed to guests. Registration is fast, simple and absolutely free .
DRM-free e-books 300x50
Reply
 
Thread Tools Search this Thread Display Modes
  #1 (permalink)  
Old May 31st, 2008, 11:13 AM
Registered User
 
Join Date: May 2008
Location: , , .
Posts: 4
Thanks: 0
Thanked 0 Times in 0 Posts
Default Difficulties converting XML to XML using XSLT

Hello,

i have this XML structure

Code:
<group>
        <name>person</name>
        <group>
            <name>caucasian</name>
            <group>
                <field>
                    <name>age</name>
                    <value>3</value>
                    <children>0</children>
                </field>
                <field>
                    <name>age</name>
                    <value>24</value>
                    <children>0</children>
                </field>
            </group>
       </group>
       <group>
            <name>asian</name>
            <group>
                <field>
                    <name>age</name>
                    <age>36</age>
                    <children>2</children>
                </field>
(...)
and i want to transform it to the following format using xsl transformations

Code:
<person>
        <caucasian>
            <age>
                 <value>3</value>
                 <children>0</children>
            </age>
            <age>
                 <value>24</value>
                 <children>0</children>
            </age>
        </caucasian>
       <asian>
            <age>
                 <value>36</value>
                 <children>2</children>
            </age>
    </asian>
(...)
I already can split to the values i want using this code

Code:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml"/>
    <xsl:template match="/">
        <xsl:apply-templates/> 
    </xsl:template>

    <xsl:template match="main">
        <xsl:apply-templates select="field"/>
    </xsl:template>

    <xsl:template match="field">
        <xsl:if test="child::*[1][self::name]">
                <xsl:value-of select="."/>
        </xsl:if>

        <xsl:if test="child::*[1][self::size]">
            <xsl:copy-of select="child::*[1]"/>
        </xsl:if>

        <xsl:if test="child::*[1][self::allow]">
            <xsl:copy-of select="child::*[1]"/>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>
however i can't make it close the <name> tag from the original in the right place.
Right now i can only get to this

Code:
(...)
<caucasian></caucasian>
            <age></age>
                 <value>3</value>
                 <children>0</children>

            <age></age>
                 <value>24</value>
                 <children>0</children>
(...)
Any help? I'm killing myself with this

Reply With Quote
  #2 (permalink)  
Old May 31st, 2008, 11:42 AM
Friend of Wrox
Points: 6,676, Level: 34
Points: 6,676, Level: 34 Points: 6,676, Level: 34 Points: 6,676, Level: 34
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Nov 2007
Location: Germany
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

Your XML sample is inconsistent, the first two 'field' elements have child elements 'value' and 'children' while the third has 'age' and 'children' child elements.
Assuming the third 'field' element also has 'value' instead of 'age' then it is easy:
Code:
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0">

  <xsl:output method="xml" indent="yes"/>

  <xsl:strip-space elements="*"/>

  <xsl:template match="/group">
    <person>
      <xsl:apply-templates select="group"/>
    </person>
  </xsl:template>

  <xsl:template match="/group/group">
    <xsl:element name="{name}">
      <xsl:apply-templates select="group/field"/>
    </xsl:element>
  </xsl:template>

  <xsl:template match="group/field">
    <age>
      <xsl:copy-of select="value | children"/>
    </age>
  </xsl:template>

</xsl:stylesheet>

--
  Martin Honnen
  Microsoft MVP - XML
Reply With Quote
  #3 (permalink)  
Old May 31st, 2008, 01:34 PM
Registered User
 
Join Date: May 2008
Location: , , .
Posts: 4
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Yes, it it value and not age.

I'm going to try what you wrote. Thank you!

Reply With Quote
  #4 (permalink)  
Old June 1st, 2008, 03:12 AM
mhkay's Avatar
Wrox Author
Points: 18,487, Level: 59
Points: 18,487, Level: 59 Points: 18,487, Level: 59 Points: 18,487, Level: 59
Activity: 100%
Activity: 100% Activity: 100% Activity: 100%
 
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

This logic looks very clumsy

<xsl:template match="field">
        <xsl:if test="child::*[1][self::name]">
                <xsl:value-of select="."/>
        </xsl:if>

Can't be definitive because you haven't said what all the input possibilities are (e.g. you mention element <allow>), but to handle your sample data (as corrected) I might write

<xsl:template match="field">
  <xsl:element name="{name}">
    <xsl:copy-of select="*[not(self::name)]"/>
  </xsl:element>
</xsl:template>

>however i can't make it close the <name> tag from the original in the right place.

Do try to think of XSLT as producing a result tree of nodes, not producing lexical XML with tags. Changing your thought process here is the first step to understanding what's going on. In the above template, the xsl:element instruction generates an element node in the result tree, and the xsl:copy-of instruction generates its children in the result tree. If you get the tree of nodes right, the tags will look after themselves.

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
Reply With Quote
  #5 (permalink)  
Old June 2nd, 2008, 01:50 PM
Registered User
 
Join Date: May 2008
Location: , , .
Posts: 4
Thanks: 0
Thanked 0 Times in 0 Posts
Default

First of all thank you for your help.

I'm close to what i want to obtain as a resulting XML, however there are a few bugs that i can't get rid of...

This is a piece of my XML code (with some edits):

Code:
<?xml version="1.0" encoding="ISO-8859-1"?>
<packet>
    <group>
        <name>ph</name>
        <offset>0</offset>
        <group>
            <name>pi</name>
            <offset>0</offset>
            <group>
                <field>
                    <name>vn</name>
                    <size>3</size>
                    <allow>0</allow>
                </field>
                <field>
                    <name>t</name>
                    <size>1</size>
                    <reserved>0</reserved>
                </field>
                <field>
                    <name>data</name>
                    <size>1</size>
                </field>
                <group>
                    <name>aid</name>
                    <offset>0</offset>
                    <group>
                        <field>
                            <name>pd</name>
                            <size>7</size>
                        </field>
                        <field>
                            <name>pt</name>
                            <size>4</size>
                        </field>
                    </group>
                </group>
            </group>
        </group>
(...)
this is my xsl

Code:
 <xsl:template match="/">
    <xsl:text disable-output-escaping="yes"><packet></xsl:text>
    <xsl:apply-templates/>
    <xsl:text disable-output-escaping="yes"></packet></xsl:text>
  </xsl:template>


  <xsl:template match="//group">
    <xsl:if test="child::node()[name()='name']">
        <xsl:text disable-output-escaping="yes"><</xsl:text>
        <xsl:value-of select="name"/>
        <xsl:text disable-output-escaping="yes">></xsl:text>
    </xsl:if>
    <xsl:apply-templates/>   
    <xsl:if test="child::node()[name()='name']">
        <xsl:text disable-output-escaping="yes"></</xsl:text>
        <xsl:value-of select="name"/>
        <xsl:text disable-output-escaping="yes">></xsl:text>
    </xsl:if>
  </xsl:template>

  <xsl:template match="group">

  </xsl:template>

  <xsl:template match="offset">
    <xsl:copy-of select="."/>
  </xsl:template>

  <xsl:template match="field">
    <xsl:element name="{name}">
      <xsl:copy-of select="size | allow | reserved"/>
    </xsl:element>
  </xsl:template>
i'm getting this result with some text in the middle... that shouldn't be there... also i'm open to suggestions for replacement of those if clauses in the beginning :)

Code:
<packet>

    <ph>
ph
<offset>0</offset>

    <pi>
pi
<offset>0</offset>

    <vn>
<size>3</size>
<allow>0</allow>
</vn>

    <t>
<size>1</size>
<reserved>0</reserved>
</t>

    <data>
<size>1</size>
</data>

    <aid>
aid
<offset>0</offset>

    <pd>
<size>7</size>
</pd>

    <pt>
<size>4</size>
</pt>
</aid>
</pi>
basically the text repeats after a "/group/name" from the original XML

Thank you
Reply With Quote
  #6 (permalink)  
Old June 2nd, 2008, 02:16 PM
mhkay's Avatar
Wrox Author
Points: 18,487, Level: 59
Points: 18,487, Level: 59 Points: 18,487, Level: 59 Points: 18,487, Level: 59
Activity: 100%
Activity: 100% Activity: 100% Activity: 100%
 
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

I can't actually see how you're getting anything: your stylesheet isn't well-formed XML. Perhaps you really wrote &lt;packet&gt; rather than <packet>?

Please don't use disable-output-escaping until you're expert enough to know that there is no other solution. It doesn't work in all environments, and that's because it creates a nasty hidden dependency on the interface between the transformer and the serializer, which should be kept independent of each other.

I said this before: "Do try to think of XSLT as producing a result tree of nodes, not producing lexical XML with tags. " and you clearly haven't taken it on board.

In this example there's no excuse:

<xsl:template match="/">
    <xsl:text disable-output-escaping="yes"><packet></xsl:text>
    <xsl:apply-templates/>
    <xsl:text disable-output-escaping="yes"></packet></xsl:text>
  </xsl:template>

that should be

<xsl:template match="/">
    <packet>
    <xsl:apply-templates/>
    </packet>
  </xsl:template>

and this

<xsl:template match="//group">
    <xsl:if test="child::node()[name()='name']">
        <xsl:text disable-output-escaping="yes"><</xsl:text>
        <xsl:value-of select="name"/>
        <xsl:text disable-output-escaping="yes">></xsl:text>
    </xsl:if>
    <xsl:apply-templates/>
    <xsl:if test="child::node()[name()='name']">
        <xsl:text disable-output-escaping="yes"></</xsl:text>
        <xsl:value-of select="name"/>
        <xsl:text disable-output-escaping="yes">></xsl:text>
    </xsl:if>
  </xsl:template>

should be two separate rules:

<xsl:template match="group[name]">
  <xsl:element name="{name}">
    <xsl:apply-templates/>
  </xsl:element>
</xsl:template>

<xsl:template match="group[not(name)]">
    <xsl:apply-templates/>
</xsl:template>

>i'm getting this result with some text in the middle... that shouldn't be there...

That's caused by processing the <name> element twice: once explicitly using value-of, and once implicitly when you do apply-templates to all children. Simplest solution is

<xsl:template match="name"/>



Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
Reply With Quote
  #7 (permalink)  
Old June 3rd, 2008, 05:39 AM
Registered User
 
Join Date: May 2008
Location: , , .
Posts: 4
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Thank you. Now it works :)

I think i will never work with XSL again. I rather prefer to code in assembly or something that i can put logic into it... i couldn't find logic in XSL... but this is just me

thanks again!

Reply With Quote
  #8 (permalink)  
Old June 3rd, 2008, 05:45 AM
mhkay's Avatar
Wrox Author
Points: 18,487, Level: 59
Points: 18,487, Level: 59 Points: 18,487, Level: 59 Points: 18,487, Level: 59
Activity: 100%
Activity: 100% Activity: 100% Activity: 100%
 
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

Yes, you're clearly someone who isn't used to coding at a high level of abstraction, and prefers to be closer to the machine. Do persist though - high level languages (and thinking in terms of higher-level abstractions) will greatly increase your effectiveness as a programmer if you can learn to get to grips with them.

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
Reply With Quote
Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Converting Source Xml into Target Xml Using XSL. alapati.sasi XSLT 3 May 14th, 2007 10:54 AM
Converting XML into a particular format using XSLT AjayLuthria XSLT 1 April 10th, 2007 09:47 AM
Converting XML to XML (making element mandatory) boondocksaint20 XSLT 8 April 28th, 2006 10:54 AM
xml and xsl templates as input to xslt gives xml rameshnarayan XSLT 5 August 3rd, 2005 01:58 AM
Merge XML files into a xml file using xslt lxu XML 4 November 6th, 2003 06:01 PM



All times are GMT -4. The time now is 06:44 AM.


Powered by vBulletin®
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd.
© 2013 John Wiley & Sons, Inc.