XSLT Identity Transformation problem

Hi all,

Any help on the following problem would be greatly appreciated.  

I need to be able to transform an XML file through several XSL files (Pipelining) whilst maintaining the basic structure of the XML to produce an XML output file.  There will only be small changes made to the XML in these XSL Stylesheets so its important to just pass through most of the XML without changing it at all.  Hence i have used

<xsl:template match="node()|@*">
      <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>  
</xsl:template>

What XSL code can I add to this stylesheet to update/add or delete some of the elements whilst passing through the rest of the XML unchanged (see below for example) ?

Input XML File:

<?xml version="1.0" standalone="yes"?>
<DataSet xmlns="http://tempuri.org/DataSet.xsd">
  <item>    
    <Key>89308F80-A3DF-4B61-8419-3EE6FF0D6E01</Key>
    <TableName>TEST1</TableName>
    <KeyPart1>1</KeyPart1>
  </Item>
  <item>    
    <Key>89308F80-A3DF-4B61-8419-3EE6FF0D6E02</Key>
    <TableName>TEST2</TableName>
    <KeyPart1>1</KeyPart1>
  </item>
</DataSet>

XSL 1:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node()|@*">
      <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>  
</xsl:template>

<!-- Insert a new element node into the Item node ???? -->
<xsl:template match="DataSet">
      <xsl:for-each select="Item">
            <NewElement>Test Info</NewElement>
      </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

XSL 2:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node()|@*">
      <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>  
</xsl:template>

<!-- Change the TableName value ???? -->
<xsl:template match="DataSet/Item">
      <xsl:for-each select="TableName">
            <TableName>Change the TableName Value</TableName>
      </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Thanks for your help

Matt
mattbelfast23Asked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
Geert BormansConnect With a Mentor Information ArchitectCommented:
If you want to control the position closer
(eg. needs to be the item after the item that contains the TEST1)
you could use a test

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="http://tempuri.org/DataSet.xsd"
    xmlns:uri="http://tempuri.org/DataSet.xsd"
    exclude-result-prefixes="uri" version="1.0">
    <xsl:template match="node()|text()">
        <xsl:copy>
            <xsl:copy-of select="@*" />
            <xsl:apply-templates select="node()|text()"/>
        </xsl:copy>  
    </xsl:template>
    <xsl:template match="uri:DataSet/uri:item">
        <xsl:copy>
            <xsl:copy-of select="@*" />
            <uri:NewElement>Test Info</uri:NewElement>
            <xsl:apply-templates select="node()|text()"/>
        </xsl:copy>
        <xsl:if test="uri:TableName/text() ='TEST1'">
            <item>    
                <Key>89308F80-A3DF-4B61-8419-3EE6FF0D6E06</Key>
                <KeyPart1>1</KeyPart1>
                <TableName>TESTNEWITEM</TableName>
            </item>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>
0
 
Geert BormansInformation ArchitectCommented:
Hi mattbelfast23,

since this is a very hierarchical approach,
you would better tackle this in the smallest particle template

so instead of
<xsl:template match="DataSet/Item">
      <xsl:for-each select="TableName">

you should have
    <xsl:template match="DataSet/Item/TableName">
           <TableName>Change the TableName Value</TableName>
    </xsl:template>

that is a lot safer as regards maintaining whitespace and all that
(so don't mix with for-each)


Cheers!
0
 
Geert BormansInformation ArchitectCommented:
mattbelfast23,
> <xsl:template match="node()|@*">
>      <xsl:copy>
>           <xsl:apply-templates select="node()|@*"/>
>      </xsl:copy>  
> </xsl:template>

I by the way prefer this style for identity copying
 
 <xsl:template match="node()|text()">
      <xsl:copy>
           <xsl:copy-of select="@*" />
           <xsl:apply-templates select="node()|text()"/>
      </xsl:copy>  
 </xsl:template>

gives me control from within the element
can't explain that this would be better or not
but I find it more convenient to change specific processing from this form
(means no templates for attributes)
your style would be better if you want to do something specific to an attribute with a certain name,
regardless of the element it is attached to

anyway, just a thought

for your XSL1 this would be the result

<xsl:template match="DataSet/Item">
      <xsl:copy>
           <xsl:copy-of select="@*" />
            <NewElement>Test Info</NewElement>
          <xsl:apply-templates select="node()|text()"/>
      </xsl:copy>  
</xsl:template>

would put a new element BEFORE the other children of Item

If you by the way want to delete a subelement in one of your pipes
you need to do this (eg. Keypart1 in Item)

<xsl:template match="Item">
      <xsl:copy>
           <xsl:copy-of select="@*" />
           <xsl:apply-templates select="node()[not(name() = 'KeyPart1')]|text()"/>
      </xsl:copy>  
 </xsl:template>


0
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
mattbelfast23Author Commented:
Hi Gertone,

Your suggestion for Deletion worked a treat, however when i tried the Addition (XSL1) of a new element it was returning the XML like this:

<?xml version="1.0" encoding="utf-8"?>13489308F80-A3DF-4B61-8419-3EE6FF0D6E01TEST113489308F80-A3DF-4B61-8419-3EE6FF0D6E02TEST213489308F80-A3DF-4B61-8419-3EE6FF0D6E03TEST3

Any ideas why this may be happening?
0
 
Geert BormansInformation ArchitectCommented:
Can you show the exact code for the addition you are using?
0
 
Geert BormansInformation ArchitectCommented:
This is what you would need:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="http://tempuri.org/DataSet.xsd"
    xmlns:uri="http://tempuri.org/DataSet.xsd"
    exclude-result-prefixes="uri" version="1.0">
    <xsl:template match="node()|text()">
        <xsl:copy>
            <xsl:copy-of select="@*" />
            <xsl:apply-templates select="node()|text()"/>
        </xsl:copy>  
    </xsl:template>
    <xsl:template match="uri:DataSet/uri:item">
        <xsl:copy>
            <xsl:copy-of select="@*" />
            <uri:NewElement>Test Info</uri:NewElement>
            <xsl:apply-templates select="node()|text()"/>
        </xsl:copy>  
    </xsl:template>
 </xsl:stylesheet>

note the namespace allocation, taken from your example XML
also note that case is important in element names
0
 
mattbelfast23Author Commented:
Hi Gertone,

Thats a great help, thanks very much.  For an extra 100 points could you please help me with this problem that follows on from your above solution?  I essentially need to match an DataSet/Item on a TableName value (TEST1).  If the TableName exists I then need to create a new DataSet/Item element at the same level as the others.  Is this possible?

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="http://tempuri.org/DataSet.xsd"
    xmlns:uri="http://tempuri.org/DataSet.xsd"
    exclude-result-prefixes="uri" version="1.0">
    <xsl:template match="node()|text()">
        <xsl:copy>
            <xsl:copy-of select="@*" />
            <xsl:apply-templates select="node()|text()"/>
        </xsl:copy>  
    </xsl:template>
    <xsl:template match="uri:DataSet/uri:item">
        <xsl:copy>
            <xsl:copy-of select="@*" />
            <uri:NewElement>Test Info</uri:NewElement>
            <xsl:apply-templates select="node()|text()"/>
        </xsl:copy>  
    </xsl:template>

   <!-- If the TableName = TEST1 create a new ITEM element at the same level as the others -->
    <xsl:template match="uri:DataSet/uri:item/uri:TableName[text()='TEST1']">
        <xsl:copy>
            <xsl:copy-of select="@*" />

<!-- I need this to be at the same level as the other item elements -->

            <item>      
            <Key>89308F80-A3DF-4B61-8419-3EE6FF0D6E06</Key>
            <KeyPart1>1</KeyPart1>
            <TableName>TESTNEWITEM</TableName>
            </item>

            <xsl:apply-templates select="node()|text()"/>
        </xsl:copy>  
    </xsl:template>
 </xsl:stylesheet>

Thanks for any help

Matt
0
 
Geert BormansInformation ArchitectCommented:
Matt,

what about this?

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="http://tempuri.org/DataSet.xsd"
    xmlns:uri="http://tempuri.org/DataSet.xsd"
    exclude-result-prefixes="uri" version="1.0">
    <xsl:template match="node()|text()">
        <xsl:copy>
            <xsl:copy-of select="@*" />
            <xsl:apply-templates select="node()|text()"/>
        </xsl:copy>  
    </xsl:template>
    <xsl:template match="uri:DataSet/uri:item">
        <xsl:copy>
            <xsl:copy-of select="@*" />
            <uri:NewElement>Test Info</uri:NewElement>
            <xsl:apply-templates select="node()|text()"/>
        </xsl:copy>  
    </xsl:template>
     <!-- If the TableName = TEST1 create a new ITEM element at the same level as the others -->
    <xsl:template match="uri:DataSet[uri:item/uri:TableName[text()='TEST1']]">
        <xsl:copy>
            <xsl:copy-of select="@*" />
            <item>    
                <Key>89308F80-A3DF-4B61-8419-3EE6FF0D6E06</Key>
                <KeyPart1>1</KeyPart1>
                <TableName>TESTNEWITEM</TableName>
            </item>
            <xsl:apply-templates select="node()|text()"/>
        </xsl:copy>  
    </xsl:template>
</xsl:stylesheet>
0
 
mattbelfast23Author Commented:
Thanks very much for your help Gertone.  Much appreciated.
0
 
Geert BormansInformation ArchitectCommented:
welcome
0
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.

All Courses

From novice to tech pro — start learning today.