XSLT Recursive Reversal of Ancestry

Discussion in 'XML' started by alex.maddern@gmail.com, Oct 18, 2007.

  1. Guest

    I have an XML file containing a hierarchical relationship between
    "Object Types". Each relationship contains a reference to the GUID for
    that Object and I have been tasked to extract these GUID's in reverse
    order into a pipe delimited file. The file will be used to delete
    these objects using the GUID as an ID, so the children need to be
    processed first

    ======================
    Sample Object Type Hierarchy
    ======================
    Not all files will be like this obviously

    TYPE1 <-- only one of Type1
    TYPE2
    TYPE3
    TYPE4
    TYPE2
    TYPE3
    TYPE4
    TYPE4
    TYPE3
    TYPE4
    TYPE5
    TYPE6
    TYPE6
    TYPE6
    TYPE4
    TYPE5
    TYPE6
    TYPE2
    TYPE3
    TYPE4

    What I am trying to achieve (given the above example) is a text file
    as follows the follows.I am pretty sure that having all the Guid's in
    one long Pipe delimited line is fine, I'm just splitting them up to
    show you the principle.

    [Type4Guid] | [Type3Guid] | [Type2Guid]
    [Type4Guid] | [Type4Guid] | [Type3Guid]
    [Type6Guid] | [Type6Guid] | [Type6Guid] | [Type5Guid] | [Type4Guid]
    [Type6Guid] | [Type5Guid] | [Type4Guid] | [Type3Guid] | [Type2Guid]
    [Type4Guid] | [Type3Guid] | [Type2Guid]
    [Type1Guid]

    Before anyone asks, I have no control over this and this is frankly
    the last way I would do all this, but I have no choice in matter. To
    be honest this smells of recursive pivoting on ancestor-or-self axis
    with position limits, but it's way over my level of skill with XSLT.

    Any guru's out there with a direction to point me in ? All help
    seriously welcomed...

    Samples as follows

    ===========
    INPUT XML
    ===========

    <?xml version="1.0" encoding="utf-8"?>
    <AssociationTreeNode xmlns:xsi="http://www.w3.org/2001/XMLSchema-
    instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

    <guid>060A2B340101010501010D12130C3EDFE6A4470035430580BD8F000000000000</
    guid>
    <objectID>78c790d6-99d8-4a65-ab39-8f660c4082d4</objectID>
    <children>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130C3DE784AA47003543058084CF000000000000</
    guid>
    <objectID>f052b382-b246-4267-9a00-cd79a95fd9f7</objectID>
    <parentAssociationType>TYPE1_TYPE2</parentAssociationType>
    <children>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130C00ED82324D00354305808C6D000000000000</
    guid>
    <objectID>75c95e90-8afc-4149-9f3b-135447e42301</objectID>
    <parentAssociationType>TYPE2_TYPE3</parentAssociationType>
    <children>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130C5E7010384D00354305805875000000000000</
    guid>
    <objectID>32f05cef-9a01-4ff6-aaf4-359b33a738a2</
    objectID>
    <parentAssociationType>TYPE3_TYPE4</
    parentAssociationType>
    <children />
    </AssociationTreeNode>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130C1476E2804D0035430580407F000000000000</
    guid>
    <objectID>32f05cef-9a01-4ff6-aaf4-359b323348a2</
    objectID>
    <parentAssociationType>TYPE3_TYPE4</
    parentAssociationType>
    <children />
    </AssociationTreeNode>
    </children>
    </AssociationTreeNode>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130C02FC4405DD0035430580AD6B000000000000</
    guid>
    <objectID>75c95e90-8afc-4149-9f3b-135447e42301</objectID>
    <parentAssociationType>TYPE2_TYPE3</parentAssociationType>
    <children>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130CB5B0200BDD003543058017C7000000000000</
    guid>
    <objectID>32f05cef-9a01-4ff6-aaf4-359b33a738a2</
    objectID>
    <parentAssociationType>TYPE3_TYPE4</
    parentAssociationType>
    <children />
    </AssociationTreeNode>
    </children>
    </AssociationTreeNode>
    </children>
    </AssociationTreeNode>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130C417052F88E00354305808CAB000000000000</
    guid>
    <objectID>f052b382-b246-4267-9a00-cd79a95fd9f7</objectID>
    <parentAssociationType>TYPE1_TYPE2</parentAssociationType>
    <children>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130C124BE667EB003543058033B7000000000000</
    guid>
    <objectID>75c95e90-8afc-4149-9f3b-135447e42301</objectID>
    <parentAssociationType>TYPE2_TYPE3</parentAssociationType>
    <children>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130CD6FBA26DEB00354305805FE8000000000000</
    guid>
    <objectID>32f05cef-9a01-4ff6-aaf4-359b33a738a2</
    objectID>
    <parentAssociationType>TYPE3_TYPE4</
    parentAssociationType>
    <children />
    </AssociationTreeNode>
    </children>
    </AssociationTreeNode>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130C29277497AD00354305808CF5000000000000</
    guid>
    <objectID>75c95e90-8afc-4149-9f3b-135447e42301</objectID>
    <parentAssociationType>TYPE2_TYPE3</parentAssociationType>
    <children>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130CE9EC7F9DAD00354305801FC2000000000000</
    guid>
    <objectID>32f05cef-9a01-4ff6-aaf4-359b33a738a2</
    objectID>
    <parentAssociationType>TYPE3_TYPE4</
    parentAssociationType>
    <children>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130C2C627CC0D00455430580053C000000000000</
    guid>
    <objectID>9214702c-0d18-40fc-b4e7-ab1ee37e7b05</
    objectID>
    <parentAssociationType>TYPE4_TYPE5</
    parentAssociationType>
    <children>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130C3DDA3C886B0335430580B38B000000000000</
    guid>
    <objectID>2ce8c725-dea1-4aeb-9a07-f988260e5180</
    objectID>
    <parentAssociationType>TYPE5_TYPE6</
    parentAssociationType>
    <children />
    </AssociationTreeNode>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130C4277C9886B03354305801240000000000000</
    guid>
    <objectID>2ce8c725-dea1-4aeb-9a07-f988260e5180</
    objectID>
    <parentAssociationType>TYPE5_TYPE6</
    parentAssociationType>
    <children />
    </AssociationTreeNode>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130C44A56B886B03354305808412000000000000</
    guid>
    <objectID>2ce8c725-dea1-4aeb-9a07-f988260e5180</
    objectID>
    <parentAssociationType>TYPE5_TYPE6</
    parentAssociationType>
    <children />
    </AssociationTreeNode>
    </children>
    </AssociationTreeNode>
    </children>
    </AssociationTreeNode>
    </children>
    </AssociationTreeNode>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130C2F30189ED2003543058082BA000000000000</
    guid>
    <objectID>75c95e90-8afc-4149-9f3b-135447e42301</objectID>
    <parentAssociationType>TYPE2_TYPE3</parentAssociationType>
    <children>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130C22D7A5A3D200354305808197000000000000</
    guid>
    <objectID>32f05cef-9a01-4ff6-aaf4-359b33a738a2</
    objectID>
    <parentAssociationType>TYPE3_TYPE4</
    parentAssociationType>
    <children>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130C28D3674A3400614305805010000000000000</
    guid>
    <objectID>9214702c-0d18-40fc-b4e7-ab1ee37e7b05</
    objectID>
    <parentAssociationType>TYPE4_TYPE5</
    parentAssociationType>
    <children>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130C4F14E2B75A0455430580F244000000000000</
    guid>
    <objectID>2ce8c725-dea1-4aeb-9a07-f988260e5180</
    objectID>
    <parentAssociationType>TYPE5_TYPE6</
    parentAssociationType>
    <children />
    </AssociationTreeNode>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130C50EEB3B75A04554305804078000000000000</
    guid>
    <objectID>2ce8c725-dea1-4aeb-9a07-f988260e5180</
    objectID>
    <parentAssociationType>TYPE5_TYPE6</
    parentAssociationType>
    <children />
    </AssociationTreeNode>
    </children>
    </AssociationTreeNode>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130C86572CF8BD03824305801925000000000000</
    guid>
    <objectID>9214702c-0d18-40fc-b4e7-ab1ee37e7b05</
    objectID>
    <parentAssociationType>TYPE4_TYPE5</
    parentAssociationType>
    <children>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130C1FF7C797BE03824305806D3E000000000000</
    guid>
    <objectID>2ce8c725-dea1-4aeb-9a07-f988260e5180</
    objectID>
    <parentAssociationType>TYPE5_TYPE6</
    parentAssociationType>
    <children />
    </AssociationTreeNode>
    </children>
    </AssociationTreeNode>
    </children>
    </AssociationTreeNode>
    </children>
    </AssociationTreeNode>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130C9580C9EB0A013543058079D6000000000000</
    guid>
    <objectID>75c95e90-8afc-4149-9f3b-135447e42301</objectID>
    <parentAssociationType>TYPE2_TYPE3</parentAssociationType>
    <children>
    <AssociationTreeNode>

    <guid>060A2B340101010501010D12130CBA4FA5F10A0135430580FE5A000000000000</
    guid>
    <objectID>32f05cef-9a01-4ff6-aaf4-359b33a738a2</
    objectID>
    <parentAssociationType>TYPE3_TYPE4</
    parentAssociationType>
    <children />
    </AssociationTreeNode>
    </children>
    </AssociationTreeNode>
    </children>
    </AssociationTreeNode>
    </children>
    </AssociationTreeNode>
     
    , Oct 18, 2007
    #1
    1. Advertising

  2. Pavel Lepin Guest

    < > wrote in
    <>:
    > I have an XML file containing a hierarchical relationship
    > between "Object Types". Each relationship contains a
    > reference to the GUID for that Object and I have been
    > tasked to extract these GUID's in reverse order into a
    > pipe delimited file. The file will be used to delete these
    > objects using the GUID as an ID, so the children need to
    > be processed first
    >
    > What I am trying to achieve (given the above example) is a
    > text file as follows the follows.I am pretty sure that
    > having all the Guid's in one long Pipe delimited line is
    > fine, I'm just splitting them up to show you the
    > principle.
    >
    > [Type4Guid] | [Type3Guid] | [Type2Guid]
    > [Type4Guid] | [Type4Guid] | [Type3Guid]
    > [Type6Guid] | [Type6Guid] | [Type6Guid] | [Type5Guid] |
    > [[Type4Guid] Type6Guid] | [Type5Guid] | [Type4Guid] |
    > [[Type3Guid] | [Type2Guid] Type4Guid] | [Type3Guid] |
    > [[Type2Guid] Type1Guid]


    [sample document snipped]

    First of all, it would've been nice of you to replace the
    actual guids with something intelligible for the purposes
    of testing. For example, the following transformation does
    just that:

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="l" match="guid"
    use="count(ancestor::AssociationTreeNode)"/>
    <xsl:template match="@*|node()">
    <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
    </xsl:template>
    <xsl:template match="guid">
    <xsl:variable name="level"
    select="count(ancestor::AssociationTreeNode)"/>
    <xsl:variable name="number"
    select=
    "
    1 +
    count
    (
    key('l' , count(ancestor::AssociationTreeNode))
    [
    following::guid
    [generate-id()=generate-id(current())]
    ]
    )
    "/>
    <xsl:copy>
    <xsl:text>Type-</xsl:text>
    <xsl:value-of select="$level"/>
    <xsl:text>-Guid-</xsl:text>
    <xsl:value-of select="$number"/>
    </xsl:copy>
    </xsl:template>
    </xsl:stylesheet>

    The problem itself seems absolutely trivial to me:

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:eek:utput method="text"/>
    <xsl:template match="AssociationTreeNode">
    <xsl:apply-templates
    select="children/AssociationTreeNode">
    <xsl:sort select="position()" order="descending"/>
    </xsl:apply-templates>
    <xsl:text>[</xsl:text>
    <xsl:apply-templates select="guid"/>
    <xsl:text>] | </xsl:text>
    </xsl:template>
    </xsl:stylesheet>

    ....seems to achieve what you want.

    pavel@debian:~/dev/xslt$ saxon -t guids_1.xml guids.xsl
    Saxon 8.8J from Saxonica
    Java version 1.5.0_11
    Warning: at xsl:stylesheet on line 2 of
    file:/var/www/dev/xslt/guids.xsl:
    Running an XSLT 1.0 stylesheet with an XSLT 2.0 processor
    Stylesheet compilation time: 504 milliseconds
    Processing file:/var/www/dev/xslt/guids_1.xml
    Building tree for file:/var/www/dev/xslt/guids_1.xml using
    class net.sf.saxon.tinytree.TinyBuilder
    Tree built in 45 milliseconds
    Tree size: 362 nodes, 3544 characters, 0 attributes
    [Type-4-Guid-7] | [Type-3-Guid-6] | [Type-6-Guid-6] |
    [Type-5-Guid-3] | [Type-6-Guid-5] | [Type-6-Guid-4] |
    [Type-5-Guid-2] | [Type-4-Guid-6] | [Type-3-Guid-5] |
    [Type-6-Guid-3] | [Type-6-Guid-2] | [Type-6-Guid-1] |
    [Type-5-Guid-1] | [Type-4-Guid-5] | [Type-3-Guid-4] |
    [Type-4-Guid-4] | [Type-3-Guid-3] | [Type-2-Guid-2] |
    [Type-4-Guid-3] | [Type-3-Guid-2] | [Type-4-Guid-2] |
    [Type-4-Guid-1] | [Type-3-Guid-1] | [Type-2-Guid-1] |
    [Type-1-Guid-1] | Execution time: 140 milliseconds
    Memory used: 609944
    NamePool contents: 18 entries in 18 chains. 8 prefixes, 8
    URIs
    pavel@debian:~/dev/xslt$

    --
    It is rare to find learned men who are clean, do not stink,
    and have a sense of humour. -- Liselotte in a letter to
    Sophie, 30 Jul 1705
     
    Pavel Lepin, Oct 18, 2007
    #2
    1. Advertising

  3. Guest

    > First of all, it would've been nice of you to replace the
    > actual guids with something intelligible for the purposes
    > of testing. For example, the following transformation does
    > just that:


    That is really neat and will help my testing a lot, thanks


    > The problem itself seems absolutely trivial to me:


    ermmm OK, but perhaps not to people who are not highly skilled in XSL
    like yourself ?


    > <xsl:stylesheet version="1.0"
    > xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    > <xsl:eek:utput method="text"/>
    > <xsl:template match="AssociationTreeNode">
    > <xsl:apply-templates
    > select="children/AssociationTreeNode">
    > <xsl:sort select="position()" order="descending"/>
    > </xsl:apply-templates>
    > <xsl:text>[</xsl:text>
    > <xsl:apply-templates select="guid"/>
    > <xsl:text>] | </xsl:text>
    > </xsl:template>
    > </xsl:stylesheet>
    >
    > ...seems to achieve what you want.


    Thank you Pavel, that is a great help to me.

    If I can only come up with a means to exclude the final | char on the
    end, testing for position() last()/first() yields various entries
    within the output. I'll have a play in the morning, thanks again!

    Al
     
    , Oct 18, 2007
    #3
  4. Pavel Lepin Guest

    < > wrote in
    <>:
    >> <xsl:stylesheet version="1.0"
    >> xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    >> <xsl:eek:utput method="text"/>
    >> <xsl:template match="AssociationTreeNode">
    >> <xsl:apply-templates
    >> select="children/AssociationTreeNode">
    >> <xsl:sort select="position()" order="descending"/>
    >> </xsl:apply-templates>
    >> <xsl:text>[</xsl:text>
    >> <xsl:apply-templates select="guid"/>
    >> <xsl:text>] | </xsl:text>
    >> </xsl:template>
    >> </xsl:stylesheet>

    >
    > If I can only come up with a means to exclude the final |
    > char on the end, testing for position() last()/first()
    > yields various entries within the output.


    That's because position() returns the context position
    within the current node list. To check whether a node is
    the topmost node of your hierarchy, you should check its
    ancestors:

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:eek:utput method="text"/>
    <xsl:template match="AssociationTreeNode">
    <xsl:apply-templates select="." mode="r"/>
    <xsl:text> | </xsl:text>
    </xsl:template>
    <xsl:template
    match=
    "
    AssociationTreeNode
    [not(ancestor::AssociationTreeNode)]
    ">
    <xsl:apply-templates select="." mode="r"/>
    </xsl:template>
    <xsl:template match="AssociationTreeNode" mode="r">
    <xsl:apply-templates
    select="children/AssociationTreeNode">
    <xsl:sort select="position()" order="descending"/>
    </xsl:apply-templates>
    <xsl:text>[</xsl:text>
    <xsl:apply-templates select="guid"/>
    <xsl:text>]</xsl:text>
    </xsl:template>
    </xsl:stylesheet>

    --
    It is rare to find learned men who are clean, do not stink,
    and have a sense of humour. -- Liselotte in a letter to
    Sophie, 30 Jul 1705
     
    Pavel Lepin, Oct 18, 2007
    #4
  5. Guest

    > That's because position() returns the context position
    > within the current node list. To check whether a node is
    > the topmost node of your hierarchy, you should check its
    > ancestors:


    Outstanding Pavel, thank you again. I'm certainly learning a lot from
    this.

    Al
     
    , Oct 18, 2007
    #5
    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. Michael
    Replies:
    74
    Views:
    1,699
    Dhruv
    Dec 24, 2003
  2. M. Norton

    Bit reversal and IRC

    M. Norton, May 11, 2006, in forum: VHDL
    Replies:
    11
    Views:
    3,032
    Mike Treseler
    May 12, 2006
  3. Sathyaish

    in-place string reversal

    Sathyaish, Mar 28, 2006, in forum: Python
    Replies:
    12
    Views:
    773
    Felipe Almeida Lessa
    Mar 28, 2006
  4. Replies:
    6
    Views:
    357
    Robert Bachmann
    Mar 17, 2005
  5. Frederick Gotham

    Memory-reversal Game

    Frederick Gotham, Sep 8, 2006, in forum: C Programming
    Replies:
    25
    Views:
    697
    Dave Thompson
    Sep 21, 2006
Loading...

Share This Page