Adding missing output elements to an identity transform (newbie-ish)

Discussion in 'XML' started by Kolossi, Sep 13, 2005.

  1. Kolossi

    Kolossi Guest

    After reading lots of helpful posts here, and www.dpawson.co.uk, I
    think I've got the hang of processing exceptions to the identity
    transform (I'll call it "identity-"), but have a reasonably
    straightforward problem that I'd like to find the most elegant solution
    to.

    I need to do an identity transform, but if certain elements are
    missing, add them, (I'll call this "identity+"). Since XSL rules are
    based on matching elements, I can't see how to code a rule as an
    exception to the identity transform if I haven't got any input to match
    it on.

    Here's an example. I want to copy the input, but if it doesn't have an
    <author> element anywhere under the root node, I want to add one at the
    end, so I want to turn

    <a>
    <b>foo</b>
    <c>bar</c>
    <d>boof</d>
    </a>

    into

    <a>
    <b>foo</b>
    <c>bar</c>
    <d>boof</d>
    <author>UNKNOWN</author>
    </a>

    but just identity transform

    <a>
    <author>me<author>
    <e>1</e>
    <f>2</f>
    </a>

    into

    <a>
    <author>me<author>
    <e>1</e>
    <f>2</f>
    </a>

    If I knew all the possible elements below the root node, I guess I
    could match the root node, then explicitly copy them all and add the
    <author> element at the end if I hadn't set a variable to say I'd found
    one, but I'm hoping there is a more elegant solution.

    TIA

    Paul Sweeney
     
    Kolossi, Sep 13, 2005
    #1
    1. Advertising

  2. Kolossi schrieb:
    > After reading lots of helpful posts here, and www.dpawson.co.uk, I
    > think I've got the hang of processing exceptions to the identity
    > transform (I'll call it "identity-"), but have a reasonably
    > straightforward problem that I'd like to find the most elegant solution
    > to.

    ....

    Try somthing like this:

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

    <xsl:template match="a[count(author)=1]">
    <xsl:apply-templates />
    </xsl:template>

    <xsl:template match="a[count(author)=0]">
    <xsl:element name="author">unknown</xsl:element>
    <xsl:apply-templates />
    </xsl:template>


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

    HIH

    Jo
     
    =?ISO-8859-1?Q?Joachim_Wei=DF?=, Sep 13, 2005
    #2
    1. Advertising

  3. Kolossi

    Joris Gillis Guest

    Tempore 19:54:02, die Tuesday 13 September 2005 AD, hinc in foro {comp.text.xml} scripsit Joachim Weiß <>:

    > Kolossi schrieb:
    >> After reading lots of helpful posts here, and www.dpawson.co.uk, I
    >> think I've got the hang of processing exceptions to the identity
    >> transform (I'll call it "identity-"), but have a reasonably
    >> straightforward problem that I'd like to find the most elegant solution
    >> to.

    > ...
    >
    > Try somthing like this:
    >
    > <xsl:template match="/">
    > <xsl:apply-templates />
    > </xsl:template>
    >
    > <xsl:template match="a[count(author)=1]">
    > <xsl:apply-templates />
    > </xsl:template>
    >
    > <xsl:template match="a[count(author)=0]">
    > <xsl:element name="author">unknown</xsl:element>
    > <xsl:apply-templates />
    > </xsl:template>


    "a[author]" and "a[not(author)]" would also work

    --
    Joris Gillis (http://users.telenet.be/root-jg/me.html)
    «Et ipsa scientia potestas est» - Francis Bacon , Meditationes sacrae
     
    Joris Gillis, Sep 13, 2005
    #3
  4. Joris Gillis schrieb:
    >
    > "a[author]" and "a[not(author)]" would also work
    >

    You're right! this is much better than counting!
     
    =?UTF-8?B?Sm9hY2hpbSBXZWnDnw==?=, Sep 13, 2005
    #4
  5. Kolossi

    Kolossi Guest

    Thanks to both Joachim and Joris, great answers! :)

    Unfortunately, I over-simpified my example, as the "real" problem has
    multiple of these potentially-missing elements, so maybe I have to add
    default values for

    <author>UNKNOWN</author>
    <title>UNKNOWN</title>
    <location>
    <physical>UNKNOWN</physical>
    <web>http://UNKNOWN</web>
    </location>

    of course all, some or none of these could be missing in the input.

    So how could I extend your solution to multiple elements?

    Thanks for your help

    Paul Sweeney
     
    Kolossi, Sep 14, 2005
    #5
  6. Kolossi schrieb:
    > Thanks to both Joachim and Joris, great answers! :)
    >
    > Unfortunately, I over-simpified my example, as the "real" problem has
    > multiple of these potentially-missing elements, so maybe I have to add
    > default values for
    >


    Hi Paul,

    <xsl:template match="a">
    <xsl:if test="not(author)">
    <xsl:element ...
    </xsl:if>
    <xsl:if test="not(title)">
    <xsl:element ...
    </xsl:if>
    ...

    <xsl:apply-templates />
    </xsl:template>


    would be my first quick and dirty approach to this
    if you need a flexible solution, eg if the structure of your input
    varies, i would use sth like this

    my test input:

    <?xml version="1.0" encoding="UTF-8"?>
    <in>
    <a>
    <b>defined</b>
    <c>defined</c>
    <d>always defined</d>
    <link>www.somwhere.com</link>
    </a>
    <a>
    <d>always defined</d>
    <link>www.nowhere.com</link>
    </a>

    <a>
    <c>defined</c>
    <d>always defined</d>
    </a>
    </in>


    ------------------------------
    the stylesheet

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <xsl:eek:utput method="xml" />
    <xsl:template match="/">
    <xsl:apply-templates />
    </xsl:template>

    <xsl:template match="in">
    <xsl:element name="out">
    <xsl:apply-templates />
    </xsl:element>
    </xsl:template>

    <!-- here come the interesting part -->
    <xsl:template match="a">
    <xsl:element name="a">
    <!-- calling the check template -->
    <xsl:call-template name="check">
    <!-- with the node name to check as param -->
    <xsl:with-param name="node">b</xsl:with-param>
    </xsl:call-template>
    <xsl:call-template name="check">
    <xsl:with-param name="node">c</xsl:with-param>
    </xsl:call-template>

    <!-- for links we construct a special template -->
    <xsl:call-template name="link" />

    <xsl:apply-templates />
    </xsl:element>
    </xsl:template>

    <xsl:template name="check">
    <xsl:param name="node" />
    <!-- if the node does not exist -->
    <xsl:if test="not(*[name()=$node])">
    <!-- create it with the value undefined -->
    <xsl:element name="{$node}">undefined</xsl:element>
    </xsl:if>
    </xsl:template>

    <!-- the special link template -->
    <xsl:template name="link">
    <xsl:if test="not(link)">
    <xsl:element name="link">www.undefined.com</xsl:element>
    </xsl:if>
    </xsl:template>

    <!-- default work -->
    <xsl:template match="*">
    <xsl:copy>
    <xsl:apply-templates />
    </xsl:copy>
    </xsl:template>

    </xsl:stylesheet>

    ---------------------

    Hope it helps


    Jo
     
    =?ISO-8859-1?Q?Joachim_Wei=DF?=, Sep 14, 2005
    #6
  7. Kolossi

    Joris Gillis Guest

    Hi,

    Tempore 11:15:47, die Wednesday 14 September 2005 AD, hinc in foro {comp.text.xml} scripsit Kolossi <>:

    > Unfortunately, I over-simpified my example, as the "real" problem has
    > multiple of these potentially-missing elements, so maybe I have to add
    > default values for
    >
    > <author>UNKNOWN</author>
    > <title>UNKNOWN</title>
    > <location>
    > <physical>UNKNOWN</physical>
    > <web>http://UNKNOWN</web>
    > </location>
    >
    > of course all, some or none of these could be missing in the input.


    Here's a juicy generic solution:

    <xsl:stylesheet version="1.0" xmlns:var="myvar"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:eek:utput method="xml" indent="yes"/>

    <var:root>
    <author>UNKNOWN</author>
    <title>UNKNOWN</title>
    <location>
    <physical>UNKNOWN</physical>
    <web>http://UNKNOWN</web>
    </location>
    </var:root>

    <xsl:variable name="var" select="document('')/xsl:stylesheet/var:root"/>

    <xsl:template match="*">
    <xsl:element name="{local-name()}">
    <xsl:copy-of select="@*" />
    <xsl:variable name="names">
    <xsl:for-each select="*">
    <xsl:text/>|<xsl:value-of select="name()"/>|<xsl:text/>
    </xsl:for-each>
    </xsl:variable>
    <xsl:apply-templates select="
    $var[current()/self::a]/*
    [not(contains($names,concat('|',name(),'|')))]|
    $var[current()/self::location]/location/*
    [not(contains($names,concat('|',name(),'|')))]|
    node()" />
    </xsl:element>
    </xsl:template>

    </xsl:stylesheet>


    regards,
    --
    Joris Gillis (http://users.telenet.be/root-jg/me.html)
    «Numquam mores quos extuli refero» - Seneca , Ad Lucilium I, 7
     
    Joris Gillis, Sep 14, 2005
    #7
  8. Kolossi

    Kolossi Guest

    You two guys make a great team :)

    These look like just the solutions I was after, although I haven't had
    a chance to try them yet.

    To a newbie, these also show a number of XSL techniques that are
    difficult to start to use without good examples.

    Many thanks

    Paul Sweeney.
     
    Kolossi, Sep 14, 2005
    #8
    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. Gummy
    Replies:
    4
    Views:
    383
    Gummy
    Mar 31, 2006
  2. lard
    Replies:
    3
    Views:
    1,763
    Raymond DeCampo
    Mar 12, 2006
  3. Replies:
    1
    Views:
    651
    Richard Tobin
    Oct 4, 2005
  4. gnewsgroup

    Console-ish output in a browser, how?

    gnewsgroup, Dec 20, 2007, in forum: ASP .Net
    Replies:
    17
    Views:
    661
    gnewsgroup
    Dec 22, 2007
  5. gnewsgroup

    Again: Console-ish output in a browser?

    gnewsgroup, Dec 28, 2007, in forum: ASP .Net
    Replies:
    2
    Views:
    296
    gnewsgroup
    Dec 28, 2007
Loading...

Share This Page