467,906 Members | 1,597 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 467,906 developers. It's quick & easy.

Merging children from different elements

Hi,

I have a problem that seems like it ought to be solvable with a couple
of XPath statements but after a couple of days I can't find them..

Original XML:

<People>
<PartialPerson>
<Name>Brian</Name>
<Nickname>BB</Nickname>
</PartialPerson>
<PartialPerson>
<Name>Geoffrey</Name>
<Email>ge***@hotmail.com</Email>
</PartialPerson>
<PartialPerson>
<Nickname>BB</Nickname>
<Email>br***@gmail.com</Email>
</PartialPerson>
</People>

What I want to do is collect all of the info for a given person together
by linking equal fields: e.g. to end up with this:

<People>
<CompletePerson>
<Name>Brian</Name>
<Nickname>BB</Nickname>
<Email>br***@gmail.com</Email>
</CompletePerson>
<CompletePerson>
<Name>Geoffrey</Name>
<Email>ge***@hotmail.com</Email>
</CompletePerson>
</People>

The actual data might have 6+ fields, and I don't know which will be
filled in each time. Each of the fields is guaranteed to have unique
contents within the XML file, so what I need to do is to link together
all of the child elements from any other PartialPerson where any of it's
children match the equivalent child of this one. If you see what I mean.

I've got close by doing a for-each over all of the Name fields and
collecting all others with the same Name ec., but because there is no
field that is always present I end up having to go round again and again
to catch all of the cases, and with 6 child elements to consider it
grows to ridiculous proportions.

Ummm.... Help??
Jul 22 '07 #1
  • viewed: 2029
Share:
3 Replies
Ixa
I've got close by doing a for-each over all of the Name fields and
collecting all others with the same Name
How about using <xsl:keyinstead of <Nameand just picking up relevant data?

For example:

---8<---8<---
<xsl:key name="person" match="PartialPerson" use="*"/>

<xsl:template match="/People">
<xsl:copy>
<xsl:for-each select="PartialPerson">
<xsl:variable name="identifier" select="*"/>
<xsl:if test="not(preceding-sibling::PartialPerson
[key('person', *) = key('person', $identifier)])">
<xsl:apply-templates select="."/>
</xsl:if>
</xsl:for-each>
</xsl:copy>
</xsl:template>

<xsl:template match="PartialPerson">
<CompletePerson>
<xsl:apply-templates select="key('person', *)[Name][1]/Name"/>
<xsl:apply-templates select="key('person', *)[Nickname][1]/Nickname"/>
<xsl:apply-templates select="key('person', *)[email][1]/Email"/>
</CompletePerson>
</xsl:template>

<xsl:template match="PartialPerson/*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
---8<---8<---

--
Ixa

Jul 23 '07 #2
Ixa wrote:
>I've got close by doing a for-each over all of the Name fields and
collecting all others with the same Name

How about using <xsl:keyinstead of <Nameand just picking up relevant
data?
<snip>

That works perfectly, thanks. The bit I was missing was having a key
over all of the possible elements instead of just one. I don't think I
think in enough dimensions yet to get the best out of XSL...
<xsl:if test="not(preceding-sibling::PartialPerson
[key('person', *) = key('person', $identifier)])">
This bit was interesting - I'm using Oxygen XML to develop the
transforms, and with Saxon 6.5.5 it works fine, but with the included
Xalan (Java version 2.7.0) the line above gives an 'Unknown Error in
XPath' and dies.

With Xalan-C 1.10.0 (which is what I actually need to use), it works
fine. So it's not something that I need to get fixed right now, but I'm
curious what it might be. Any ideas?
Thanks again for your help

Paul

Jul 23 '07 #3
Ixa
> <xsl:if test="not(preceding-sibling::PartialPerson
> [key('person', *) = key('person', $identifier)])">
This bit was interesting - I'm using Oxygen XML to develop the
transforms, and with Saxon 6.5.5 it works fine, but with the included
Xalan (Java version 2.7.0) the line above gives an 'Unknown Error in
XPath' and dies.
Sounds like Xalan-J has some issues with comparing node-set given by
"key"- function.

Anyhow, actually this node-set comparison can also (and should) be done
without "key"- function so that it works with Xalan-J, too. Using
"key"- functions in this test is just unnecessary. For example:

---8<---8<---
<xsl:for-each select="PartialPerson">
<xsl:variable name="children" select="*"/>
<xsl:if test="not(preceding-sibling::PartialPerson[* = $children])">
<xsl:apply-templates select="."/>
</xsl:if>
</xsl:for-each>
---8<---8<---

--
Ixa

Jul 24 '07 #4

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

6 posts views Thread by Luke Dalessandro | last post: by
17 posts views Thread by eric.nave | last post: by
3 posts views Thread by Patrick | last post: by
2 posts views Thread by Nikhil Prashar | last post: by
14 posts views Thread by etal | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.