Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
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 software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old May 31st, 2008, 11:13 AM
Registered User
 
Join Date: May 2008
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

 
Old May 31st, 2008, 11:42 AM
Friend of Wrox
 
Join Date: Nov 2007
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
 
Old May 31st, 2008, 01:34 PM
Registered User
 
Join Date: May 2008
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!

 
Old June 1st, 2008, 03:12 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
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
 
Old June 2nd, 2008, 01:50 PM
Registered User
 
Join Date: May 2008
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
 
Old June 2nd, 2008, 02:16 PM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
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
 
Old June 3rd, 2008, 05:39 AM
Registered User
 
Join Date: May 2008
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!

 
Old June 3rd, 2008, 05:45 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
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





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





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.