Merging children from different elements

Discussion in 'XML' started by PC Paul, Jul 22, 2007.

  1. PC Paul

    PC Paul Guest

    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></Email>
    </PartialPerson>
    <PartialPerson>
    <Nickname>BB</Nickname>
    <Email></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></Email>
    </CompletePerson>
    <CompletePerson>
    <Name>Geoffrey</Name>
    <Email></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??
     
    PC Paul, Jul 22, 2007
    #1
    1. Advertising

  2. PC Paul

    Ixa Guest

    > 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:key> instead of <Name> and 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', *)[1]/Email"/>
    </CompletePerson>
    </xsl:template>

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

    --
    Ixa
     
    Ixa, Jul 23, 2007
    #2
    1. Advertising

  3. PC Paul

    PC Paul Guest

    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:key> instead of <Name> and 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
     
    PC Paul, Jul 23, 2007
    #3
  4. PC Paul

    Ixa Guest

    >> <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
     
    Ixa, Jul 24, 2007
    #4
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ravi
    Replies:
    4
    Views:
    392
    Dimitre Novatchev
    Nov 10, 2003
  2. Replies:
    0
    Views:
    538
  3. Alan
    Replies:
    1
    Views:
    431
    Victor Bazarov
    Jun 4, 2007
  4. Pradeep Patra

    Merging Multiple Array elements

    Pradeep Patra, Jan 15, 2012, in forum: Perl Misc
    Replies:
    11
    Views:
    772
    J├╝rgen Exner
    Jan 15, 2012
  5. Replies:
    4
    Views:
    210
Loading...

Share This Page