[XSL] Obtaining an attribute from self or ancestor

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Ebenezer

    #1

    [XSL] Obtaining an attribute from self or ancestor

    Hello!

    Let's suppose we have an XML with some nested NODE nodes:

    <root attr="first">
    <node id="1" attr="mike">
    <node id="2" />
    <node id="3" attr="dave" />
    </node>
    <node id="4">
    <node id="5" attr="peter" />
    </node>
    </root>

    What I want to achieve is to have an XSL that:
    - takes a $id variable externally from a PHP script
    - finds the node with @id=$id
    - outputs the value "@attr" attribute IF PRESENT, otherwise the parent's
    "@attr" attribute IF PRESENT, otherwise the grandparent's.. . recursively
    traversing from parent to parent, until an @attr value is found

    This won't work for some nodes:

    <?xml version="1.0"?>
    <xsl:styleshe et version="1.0">
    <xsl:output method="html" />
    <xsl:template match="root">
    <xsl:apply-templates select="//node[@id=$id]" />
    </xsl:template>
    <xsl:template match="node">
    <xsl:choose>
    <xsl:when test="not(@attr )"><xsl:appl y-templates ".." /></xsl:when>
    <xsl:otherwise> <xsl:value-of select="@attr" /></xsl:otherwise>
    </xsl:choose>
    </xsl:template>
    </xsl:stylesheet>
  • Martin Honnen

    #2
    Re: [XSL] Obtaining an attribute from self or ancestor

    Ebenezer wrote:
    What I want to achieve is to have an XSL that:
    - takes a $id variable externally from a PHP script
    - finds the node with @id=$id
    - outputs the value "@attr" attribute IF PRESENT, otherwise the parent's
    "@attr" attribute IF PRESENT, otherwise the grandparent's.. . recursively
    traversing from parent to parent, until an @attr value is found
    >
    This won't work for some nodes:
    >
    <?xml version="1.0"?>
    <xsl:styleshe et version="1.0">
    <xsl:output method="html" />
    You need to define the id parameter
    <xsl:param name="id"/>
    <xsl:template match="root">
    <xsl:apply-templates select="//node[@id=$id]" />
    </xsl:template>
    <xsl:template match="node">
    <xsl:choose>
    <xsl:when test="not(@attr )"><xsl:appl y-templates ".."
    /></xsl:when>
    That is not the correct syntax, you need
    <xsl:apply-templates select=".."/>
    Also it is not clear what you want to do if you do not find a 'node'
    ancestor element with an 'attr' attribute.
    If you walk up to the 'root element then the template matching that will
    lead to infinite recursion. So perhaps you should better use
    <xsl:apply-templates select="parent: :node"/>
    Or if you want to walk up to the 'root' element as well you need a mode e.g.
    <xsl:apply-templates select=".." mode="attribute-check"/>

    and then you need to add that mode parameter to the template e.g.


    <xsl:template match="root">
    <xsl:apply-templates select="//node[@id=$id]"
    mode="attribute-check" />
    </xsl:template>
    <xsl:template match="node | root" mode="attribute-check">
    <xsl:choose>
    <xsl:when test="not(@attr )"><xsl:appl y-templates
    select="parent: :*" /></xsl:when>
    <xsl:otherwise> <xsl:value-of select="@attr" /></xsl:otherwise>
    </xsl:choose>
    </xsl:template>




    --

    Martin Honnen
    http://JavaScript.FAQTs.com/

    Comment

    • Ebenezer

      #3
      Re: [XSL] Obtaining an attribute from self or ancestor

      Martin Honnen ha scritto:
      Ebenezer wrote:
      >
      >What I want to achieve is to have an XSL that:
      >- takes a $id variable externally from a PHP script
      >- finds the node with @id=$id
      >- outputs the value "@attr" attribute IF PRESENT, otherwise the
      >parent's "@attr" attribute IF PRESENT, otherwise the grandparent's.. .
      >recursively traversing from parent to parent, until an @attr value is
      >found
      >>
      >This won't work for some nodes:
      >>
      ><?xml version="1.0"?>
      ><xsl:styleshee t version="1.0">
      > <xsl:output method="html" />
      >
      You need to define the id parameter
      <xsl:param name="id"/>
      Are you sure? I don't know if it's a standard behaviour, but other
      stylesheet's I've made take the parameters with no effort or definition...
      That is not the correct syntax, you need
      <xsl:apply-templates select=".."/>
      Sorry, that was my mistake in pasting the code, it's with "select" indeed...
      Also it is not clear what you want to do if you do not find a 'node'
      ancestor element with an 'attr' attribute.
      If you walk up to the 'root element then the template matching that will
      lead to infinite recursion. So perhaps you should better use
      <xsl:apply-templates select="parent: :node"/>
      Yes! There was an infinite recursion indeed but I didn't find a clue on
      it...
      Or if you want to walk up to the 'root' element as well you need a mode
      e.g.
      <xsl:apply-templates select=".." mode="attribute-check"/>
      >
      and then you need to add that mode parameter to the template e.g.
      This info was really valuable. Thanks a lot and excuse me for the multipost.

      Comment

      • Pavel Lepin

        #4
        Re: [XSL] Obtaining an attribute from self or ancestor


        Ebenezer <vaciapairat@sp am.comwrote in
        <bRgLk.86409$Ca .20678@twister2 .libero.it>:
        <root attr="first">
        <node id="1" attr="mike">
        <node id="2" />
        <node id="3" attr="dave" />
        </node>
        <node id="4">
        <node id="5" attr="peter" />
        </node>
        </root>
        >
        What I want to achieve is to have an XSL that:
        - takes a $id variable externally from a PHP script
        - finds the node with @id=$id
        - outputs the value "@attr" attribute IF PRESENT,
        otherwise the parent's "@attr" attribute IF PRESENT,
        otherwise the grandparent's.. . recursively traversing from
        parent to parent, until an @attr value is found
        <xsl:styleshe et version="1.0"
        xmlns:xsl="http ://www.w3.org/1999/XSL/Transform">
        <xsl:param name="id"/>
        <xsl:template match="/">
        <xsl:value-of select=
        "(//node[@id=$id]/ancestor-or-self::*/@attr)[last()]"
        />
        </xsl:template>
        </xsl:stylesheet>

        HTH, HAND.

        --
        If we want the average quality of computer programs to rise
        by 1000%, all we have to do is carefully to select 90% of
        the world's programmers, and shoot them. --Richard
        Heathfield in <Sfedncgr46kOPm DanZ2dnUVZ8vCdn Z2d@bt.com>

        Comment

        • Dimitre Novatchev

          #5
          Re: [XSL] Obtaining an attribute from self or ancestor

          Actually, this can be achieved with a single XPath one-liner (even without
          XSLT being involved).

          Use:

          //node[@id = $id]/ancestor-or-self::*[@attr][1]/@attr


          Cheers,
          Dimitre Novatchev


          "Ebenezer" <vaciapairat@sp am.comwrote in message
          news:bRgLk.8640 9$Ca.20678@twis ter2.libero.it. ..
          Hello!
          >
          Let's suppose we have an XML with some nested NODE nodes:
          >
          <root attr="first">
          <node id="1" attr="mike">
          <node id="2" />
          <node id="3" attr="dave" />
          </node>
          <node id="4">
          <node id="5" attr="peter" />
          </node>
          </root>
          >
          What I want to achieve is to have an XSL that:
          - takes a $id variable externally from a PHP script
          - finds the node with @id=$id
          - outputs the value "@attr" attribute IF PRESENT, otherwise the parent's
          "@attr" attribute IF PRESENT, otherwise the grandparent's.. . recursively
          traversing from parent to parent, until an @attr value is found
          >
          This won't work for some nodes:
          >
          <?xml version="1.0"?>
          <xsl:styleshe et version="1.0">
          <xsl:output method="html" />
          <xsl:template match="root">
          <xsl:apply-templates select="//node[@id=$id]" />
          </xsl:template>
          <xsl:template match="node">
          <xsl:choose>
          <xsl:when test="not(@attr )"><xsl:appl y-templates ".." /></xsl:when>
          <xsl:otherwise> <xsl:value-of select="@attr" /></xsl:otherwise>
          </xsl:choose>
          </xsl:template>
          </xsl:stylesheet>

          Comment

          • Richard Tobin

            #6
            Re: [XSL] Obtaining an attribute from self or ancestor

            In article <490139f9$0$170 67$6e1ede2f@rea d.cnntp.org>,
            Dimitre Novatchev <dnovatchev@cnn tp.orgwrote:
            >Actually, this can be achieved with a single XPath one-liner (even without
            >XSLT being involved).
            >
            >Use:
            >
            //node[@id = $id]/ancestor-or-self::*[@attr][1]/@attr
            Or, if you find it clearer not to repeat @attr:

            (//node[@id = $id]/ancestor-or-self::*/@attr)[last()]

            -- Richard
            --
            Please remember to mention me / in tapes you leave behind.

            Comment

            • Dimitre Novatchev

              #7
              Re: [XSL] Obtaining an attribute from self or ancestor


              "Richard Tobin" <richard@cogsci .ed.ac.ukwrote in message
              news:gdsk17$2hb q$1@pc-news.cogsci.ed. ac.uk...
              In article <490139f9$0$170 67$6e1ede2f@rea d.cnntp.org>,
              Dimitre Novatchev <dnovatchev@cnn tp.orgwrote:
              >
              >>Actually, this can be achieved with a single XPath one-liner (even without
              >>XSLT being involved).
              >>
              >>Use:
              >>
              > //node[@id = $id]/ancestor-or-self::*[@attr][1]/@attr
              >
              Or, if you find it clearer not to repeat @attr:
              >
              (//node[@id = $id]/ancestor-or-self::*/@attr)[last()]
              >
              This may be "clearer" but risks to be less efficient.

              Using [1] in a reverse axis is a strong optimization hint and a clever XPath
              engine will not traverse the whole way up -- it wil just stop on the first
              self-or-ancestor element found that has an "attr" attribute.

              Cheers,
              Dimitre Novatchev


              Comment

              • Richard Tobin

                #8
                Re: [XSL] Obtaining an attribute from self or ancestor

                In article <490386ab$0$170 66$6e1ede2f@rea d.cnntp.org>,
                Dimitre Novatchev <dnovatchev@cnn tp.orgwrote:
                > (//node[@id = $id]/ancestor-or-self::*/@attr)[last()]
                >This may be "clearer" but risks to be less efficient.
                >
                >Using [1] in a reverse axis is a strong optimization hint and a clever XPath
                >engine will not traverse the whole way up -- it wil just stop on the first
                >self-or-ancestor element found that has an "attr" attribute.
                True, but unlikely to be significant when the axis is ancestor-or-self,
                because XML documents tend to be much shallower than they are wide.
                For preceding-sibling it would be much more likely to make a difference.

                -- Richard
                --
                Please remember to mention me / in tapes you leave behind.

                Comment

                Working...