By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,948 Members | 838 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,948 IT Pros & Developers. It's quick & easy.

Output all same-name children of a node

P: n/a
Forgive a newbie, please:

I've got XML like this:
<body>
<block>
<p>content of p1</p>
<p>content of p2</p>
<p>content of p3</p>
...
<p>content of pN</p>
</block>
</body>

How can I write an XSLT to spit out the contents of every <pelement,
separated by <ptags?

This generates the entire contents of the <blockelement, of course,
but all in a blob:
<xsl:for-each select="body">
<xsl:value-of select="block">
</xsl:value-of>
</xsl:for-each>

And this generates the contents of the first <pelement followed by a
<ptag, but not the remaining <pelements (again, of course):
<xsl:for-each select="nitf/body/body.content/block">
<xsl:value-of select="p"></xsl:value-of>
<p></p>
</xsl:for-each>

I'm sure I'm missing something very simple ...

Apr 19 '07 #1
Share this Question
Share on Google+
4 Replies


P: n/a
Stan wrote:
How can I write an XSLT to spit out the contents of every <pelement,
separated by <ptags?
What you've already got is, in fact, more correct HTML than what you're
trying to produce, since <pmeans "start a paragraph". End-paragraph
(</p>) tags also exist in HTML and really should be used, but people
have gotten sloppy abou that since HTML processors will try to guess
where they should have been and recreate them.

If you really insist on doing what you've asked for, it's possible. What
you want to do is rip the content out of every <pelement and replace
it with the content preceeded by (or followed bya <pelement. Your
second attempt is close, but value-of returns only the value of the
*first* node matching the selection. If you want to process them all,
you need another for-each... or, better, you need to replace your
for-eaches with apply-template calls and let XSLT's normal recursive
processing do the work for you.

For example, I'd solve this with:
<xsl:template match="p">
<xsl:apply-templates/>
<p/>
</xsl:template>

which is a template that matches <pelements and replaces them with
their content followed by an empty paragraph, sloppy-HTML style. Note
that because this uses apply-templates to retrieve its content, rather
than value-of, it leaves you free to plug in templates to process other
markup that might be present within the paragraph's content.

Whether that's the best solution will depend on what the rest of your
stylesheet looks like and whether you care about the extra <pat the
end (which can be suppressed with some additional coding).
Learn to think in terms of apply-templates rather than explicit for-each
loops, at least as your first solution. Use for-each only if you really
need a special-case "anonymous local template".

--
Joe Kesselman / Beware the fury of a patient man. -- John Dryden
Apr 19 '07 #2

P: n/a

Joseph Kesselman wrote:
Stan wrote:
>How can I write an XSLT to spit out the contents of every
<pelement, separated by <ptags?
[solution]
which is a template that matches <pelements and replaces
them with their content followed by an empty paragraph,
sloppy-HTML style.
Note that as far as I can tell the HTML serializer is quite
likely to spit out '<p></p>' instead of just '<p>' for the
result tree like that, since p element's content model is
not empty.

Anyway, it just doesn't make much sense to produce sloppy
HTML (that, depending on context, may be outright invalid),
when it's so easy to do the Right Thing with XSLT.
Use for-each only if you really need a special-case
"anonymous local template".
In seculum seculorum, amen.

The biggest mystery of XSLT for me is why the omniscient
alpha geeks who wrote the specs called the darned
thing 'for-each'. They probably understood what it really
was far better than I do, after all.

--
Pavel Lepin
Apr 20 '07 #3

P: n/a
On Apr 19, 6:55 pm, Joseph Kesselman <keshlam-nos...@comcast.net>
wrote:
Stan wrote:
How can I write an XSLT to spit out the contents of every <pelement,
separated by <ptags?

What you've already got is, in fact, more correct HTML than what you're
trying to produce
I see that my example wasn't clear. I'm not trying to produce empty
paragraphs; I'm trying to put the contents of each <pnode in the XML
inside a <ptag. I actually expected that my first block of code
would work; I expected the <pnodes in the <blocknode to render the
same way <pHTML tags render, but they don't. This code:
<xsl:for-each select="body">
<xsl:value-of select="block">
</xsl:value-of>
</xsl:for-each>
produces this:
content of p1content of p2content of p3...content of pN
when I want this:
p>content of p1</p>
<p>content of p2</p>
<p>content of p3</p>
...
<p>content of pN</p>

BUT, this:
better, you need to replace your
for-eaches with apply-template calls and let XSLT's normal recursive
processing do the work for you.

For example, I'd solve this with:
<xsl:template match="p">
<xsl:apply-templates/>
<p/>
</xsl:template>
was an ah-hah moment for me. Works perfectly, and advanced my (so far
very limited) understanding considerably. Thank you very much!!
-Stan

Apr 20 '07 #4

P: n/a
On Apr 20, 6:10 pm, Stan <sdmil...@ap.orgwrote:
On Apr 19, 6:55 pm, Joseph Kesselman
<keshlam-nos...@comcast.netwrote:
Stan wrote:
How can I write an XSLT to spit out the contents of
every <pelement, separated by <ptags?
What you've already got is, in fact, more correct HTML
than what you're trying to produce

I see that my example wasn't clear. I'm not trying to
produce empty paragraphs; I'm trying to put the contents
of each <pnode in the XML inside a <ptag.
Forget the tags. There are no tags, only nodes. Once you
see the nodes, you see the matrix. But I think I understand
what you're getting at.
BUT, this:
For example, I'd solve this with:
<xsl:template match="p">
<xsl:apply-templates/>
<p/>
</xsl:template>

was an ah-hah moment for me. Works perfectly, and
advanced my (so far very limited) understanding
considerably.
And now consider this:

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

Unless I'm much mistaken, this should work even better for
you, and should be even more of an eye-opener. (It also was
what Joseph meant when he said your XML was closer to valid
HTML than what you seemed to want as an output of your
transformation.)

--
roy axenov

Apr 21 '07 #5

This discussion thread is closed

Replies have been disabled for this discussion.