Subject: How can i use xsl:copy-of in xsl
Posted By: sampath.bandaru Post Date: 7/14/2008 7:53:49 AM
I have a XML like
<Attribute>
    <NAME>ROHAN</NAME>
    <VALUE>111</VALUE>
    <AGE>23</AGE>
</Attribute>

and i want to copy the entire Attribute node except one field i.e., AGE. How can i do it in the XSL. How to use xsl:copy-of for this or are there any more ways to do? Please let me know if knows.

 Thanks in Advance.

Sampath Kumar.B
Reply By: mhkay Reply Date: 7/14/2008 7:57:14 AM
The standard coding pattern for this is to write an identity template which copies everything recursively:

<xsl:template match="*">
  <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:apply-templates/>
  </xsl:copy>
</xsl:template>

and then override it where you want different behaviour:

<xsl:template match="AGE"/>



Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
Reply By: akentanaka Reply Date: 7/21/2008 7:04:04 AM
Hi Michael,

I've seen in a book how to ignore an element as below

<xsl:apply-templates select="*[not(self::element-to-ignore)]"/>

But I can't make it to use in the sample given by sampath above.

Also, if my XML is below

<values>
<field name="Sam">TP field1 value</field>
<field name="Jean">TP field2 value</field>
<field name="John">TP field3 value</field>
<field name="Tommy">TP field4 value</field>
</values>

and I don't want the //field[@name='Tommy'] to be included in the final document?

How can I do that in a simple xslt?

Thanks!

Reply By: samjudson Reply Date: 7/21/2008 7:13:55 AM
<xsl:apply-templates select="*[not(@name='Tommy')]"/>

/- Sam Judson : Wrox Technical Editor -/
Reply By: akentanaka Reply Date: 7/21/2008 7:21:13 AM
Oh Sam,

how can I miss that?

grrr.

Thanks!

Reply By: akentanaka Reply Date: 7/23/2008 8:15:23 AM
What if the xml looks like this

<sql>
<row>
<column name="field1">Worklog</column>
<column name="field2">Age1</column>
<column name="field3">Value 1</column>
</row>
<row>
<column name="field1">Name2</column>
<column name="field2">Age2</column>
<column name="field3">Value 2</column>
</row>
<row>
<column name="field1">Worklog</column>
<column name="field2">Age3</column>
<column name="field3">Value 1</column>
</row>
<row>
<column name="field1">Name4</column>
<column name="field2">Age4</column>
<column name="field3">Value 4</column>
</row>
<row>
<column name="field1">Worklog</column>
<column name="field2">Age4</column>
<column name="field3">Value 1</column>
</row>
</sql>

And I want to ignore the ENTIRE row where it satisfies this condition //column[@name='field3']/text()='Value 4'?

I thought it's just

*[not(/row/column[@name='field3']/text()='Value 4')]

Still confused...

Reply By: mhkay Reply Date: 7/23/2008 8:25:27 AM
Any path expression starting with "/" selects from the root of the document, so you don't want it if you are trying to look at an individual row.

Try

<xsl:copy-of select="row[not(column[@name='field3']='Value 4')]"/>

assuming your context node is the <sql> element.

Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer's Reference
Reply By: samjudson Reply Date: 7/23/2008 8:26:53 AM
The above xpath expression will match the following elements:

select all children where there not a row in the document whose column name is 'field3' and column value is 'Value 4'.

What is doesn't tell us is what you want to select children of. But I suspect you're problem is the /row - which selected all row elements in the document, not the current element.

/row[not(column[@name='field3' and text()='Value 4'])]


/- Sam Judson : Wrox Technical Editor -/
Reply By: akentanaka Reply Date: 7/24/2008 1:21:24 AM
Hi Michael and Sam,

As always you guys are brilliant!

From this
*[not(/row/column[@name='field3']/text()='Value 4')]

To this

row[not(column[@name='field3']='Value 4')]

 or

row[not(column[@name='field3' and text()='Value 4'])]

Whoa!  I am not even close.  

The position of "not" and "row" and the absence or awkward position of "text()" in your solution worries me a lot about my career in XML.  

Your solution will surely go down to my notes for sure as reference.

Thanks!






Reply By: akentanaka Reply Date: 9/30/2008 11:16:23 PM
I am now stuck in removing a block of text that has prefix as

.
.
.
  <ats:MyDataItem>
    <ats:field>data1</ats:field>
    <ats:value>data1</ats:value>
    <ats:field>data2</ats:field>
    <ats:value>data2</ats:value>
  </ats:MyDataItem>
.
.
.

I want to remove <ats:MyDataItem> by using a blank template but I have no luck.

Thanks for the usual help.

Reply By: mhkay Reply Date: 10/1/2008 3:14:30 AM
A few points:

(a) Your title is confusing. Your question is not about xsl:copy-of. When asking a new question, please start a new thread.

And when asking any question, please show your input, your desired output, your attempt at solving it, and any error messages.

(b) I don't know what you mean by a "block of text". XSLT operates on trees, not on text. Do you mean you want to remove the <ats:MyDataItem> element and all its descendant nodes?

(c) "Using a blank template" suggests that you have got the basic idea that a template like <xsl:template match="ats:MyDataItem"/> causes this element not to be copied to the result tree.

(d) "has prefix" suggests that your problem is with namespaces, or at least that you think it is. But since you haven't shown any code, I can't tell what you have done wrong.

Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer's Reference
Reply By: akentanaka Reply Date: 10/1/2008 3:37:51 AM
Hi Michael,

Sorry for bumping on an old thread (which is not even mine) that has the same problem scenario.

I found the solution to my problem.  I looked at this http://www.dpawson.co.uk/xsl/sect2/N5536.html#d7672e187 which I found through one of your responses in this forum too.

Thanks!


Go to topic 74305

Return to index page 1