Newbie: Only select certain nodes in an xsl:template match

D

David Cater

This seems like a simple task, but I'm banging my head against it.
Something about XML/XPath just isn't clicking for me yet. Here's some
sample XML:

<people>
<person name="David">
Person 1 text
<child age="13">Ruby</child>
<child age="15">Rosie</child>
</person>
<person name="Wes">
Person 2 text
<child age="5">Erin</child>
<child age="2">Rowan</child>
</person>
</people>

If I want to copy everything, I can do that with this XSL:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:eek:utput method="xml" indent="yes" />
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

What if I only want to copy the nodes where person name="David"? I'm trying
to think about how the parser is processing this, and where some sort of
pattern/predicate would go, and none of my experiments to try to get that to
work are working at all.

Thanks,

David
 
D

David Cater

Fantastic.

So based on my understanding of XSL, what that basically says is:

- Match everything that is an attribute or is a node.
- In that template, copy the external tag for what was matched, and then
apply remaining templates.
- Because @*|node() continues to match, the recursive nature of the template
ends up hitting every attribute and node in the XML file.
- There is an additional template that specifically matches every node that
is a "person" and has an attribute called "name" with a value that is not
"David". That template is empty, so it generates no output.

Thanks for the tip on looking up "identity transformation". I didn't know
that's what it was called, and it helps a lot to have the nomenclature.

David

roy axenov said:
David said:
<people>
<person name="David">
Person 1 text
<child age="13">Ruby</child>
<child age="15">Rosie</child>
</person>
<person name="Wes">
Person 2 text
<child age="5">Erin</child>
<child age="2">Rowan</child>
</person>
</people>
What if I only want to copy the nodes where person
name="David"?

<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<!-- Not to worry, m'dear boy! -->

<!-- Captain Identity... -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- ...and his trusty sidekick -->
<!-- Exclusiontemplateman... -->
<xsl:template match="person[@name!='David']"/>
<!-- ...are gonna save the day. -->
</xsl:stylesheet>
 
R

roy axenov

David said:
<people>
<person name="David">
Person 1 text
<child age="13">Ruby</child>
<child age="15">Rosie</child>
</person>
<person name="Wes">
Person 2 text
<child age="5">Erin</child>
<child age="2">Rowan</child>
</person>
</people>

If I want to copy everything, I can do that with this XSL:

[nah, that's just plain wrong.]
What if I only want to copy the nodes where person
name="David"?

<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<!-- Not to worry, m'dear boy! -->

<!-- Captain Identity... -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- ...and his trusty sidekick -->
<!-- Exclusiontemplateman... -->
<xsl:template match="person[@name!='David']"/>
<!-- ...are gonna save the day. -->
</xsl:stylesheet>

I would recommend looking up something about identity
transformation and related topics. XSLT FAQ might be a good
place to start.
 
P

Pavel Lepin

David Cater said:
roy axenov said:
David said:
What if I only want to copy the nodes where person
name="David"?

<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="person[@name!='David']"/>
</xsl:stylesheet>
So based on my understanding of XSL, what that basically
says is:

- Match everything that is an attribute or is a node.

Precisely. Note that nodes are not just elements, but text
nodes (and even more esoteric PIs and comments) as well.
- In that template, copy the external tag for what was
matched, and then apply remaining templates.

It would be more correct to say that the template in
question makes a shallow copy of current node or attribute
('tags' don't really come into it, and don't make much
sense overall in XML world, they're just a serialization
detail), then applies templates to all its attributes and
children in context of this copy, but you seem to have
grasped the idea.
- Because @*|node() continues to match, the recursive
nature of the template ends up hitting every attribute and
node in the XML file.

....unless the stylesheet excludes something (which it does).
- There is an additional template that specifically
matches every node that is a "person" and has an attribute
called "name" with a value that is not "David". That
template is empty, so it generates no output.

Absolutely. And thanks to XSLT template specificity rules
you don't even have to fool around with priority
attribute - it works even without that.
 
P

Peter Flynn

David said:
This seems like a simple task, but I'm banging my head against it.
Something about XML/XPath just isn't clicking for me yet. Here's some
sample XML:

<people>
<person name="David">
Person 1 text
<child age="13">Ruby</child>
<child age="15">Rosie</child>
</person>

Don't do this. Enclose the random text. Do:

<people>
<person name="David">
<description>Person 1 text</description>
<child age="13">Ruby</child>
<child age="15">Rosie</child>
</person>
<person name="Wes">
<description>Person 2 text</description>
<child age="5">Erin</child>
<child age="2">Rowan</child>
</person>
</people>

Having loose, unmarked text floating around inside a rigid structure is
A Bad Idea.

Mixed Content (intermingled text and elements) is standard in the
textual element types of normal text documents (eg within <P> in HTML)
but almost always wrong anywhere else.

///Peter
 
J

Joe Kesselman

Peter said:
Having loose, unmarked text floating around inside a rigid structure is
A Bad Idea.

Depends on your application. Mixed content is standard within
document-oriented uses of XML (which includes XHTML, Docbook, and many
others that model annotated text). It is usually -- but not always! --
suboptimal for data-oriented uses of XML.

"Absolutes are always inherently false. Including this one."
 
P

Pavel Lepin

Joe Kesselman said:
Depends on your application. Mixed content is standard
within document-oriented uses of XML (which includes
XHTML, Docbook, and many others that model annotated
text). It is usually -- but not always! -- suboptimal for
data-oriented uses of XML.

Well, that's precisely what Peter said (using the language
that's probably a bit more understandable for a person new
to XML, such as the OP).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,990
Messages
2,570,211
Members
46,796
Latest member
SteveBreed

Latest Threads

Top