[Newbie] Output something using XSLT even if an element is missing in some documents?

Discussion in 'XML' started by John Larson, Sep 27, 2008.

  1. John Larson

    John Larson Guest

    Hi All,

    I am some information from INSPEC database records in XML to build a
    relational database of my own. I am currently trying to extract information
    by doing an XSLT transform of the XML files into a tab-separated text file
    that I want to import into the database. I have run into the following
    problem: in some documents there are missing elements, for instance the
    volume and issue number of an article is not there (i.e. it is defined in
    the DTD, but the element that contains these values happen not to be
    included in some documents). This causes a problem because it messes up my
    columns as all the rest of the elements I am extracting move left and thus
    are placed in wrong columns.

    My question is: is there some way in XSLT output a value like "empty" or
    "N/A" when some elements are missing?

    I use Xalan to do the transformations, and Altova XML spy / Stylevison to
    create the XLSTs. Please find a excerpt from my XLST file below; it is the
    "vol", "ino" and "voliss" elements that are sometimes empty.

    Thank you for any help!

    - John

    <xsl:for-each select="bibliog">
    <xsl:for-each select="jrefg">
    <xsl:for-each select="jrog">
    <xsl:for-each select="jt">
    <xsl:apply-templates/>
    </xsl:for-each>
    <xsl:text> </xsl:text>
    <xsl:for-each select="ajt">
    <xsl:apply-templates/>
    </xsl:for-each>
    <xsl:text> </xsl:text>
    <xsl:for-each select="vid">
    <xsl:for-each select="vol">
    <xsl:apply-templates/>
    </xsl:for-each>
    <xsl:text> </xsl:text>
    <xsl:for-each select="ino">
    <xsl:apply-templates/>
    </xsl:for-each>
    <xsl:text> </xsl:text>
    <xsl:for-each select="voliss">
    <xsl:apply-templates/>
    </xsl:for-each>
    </xsl:for-each>
    <xsl:text> </xsl:text>
    <xsl:for-each select="pgn">
    <xsl:apply-templates/>
    </xsl:for-each>
    <xsl:text> </xsl:text>
    </xsl:for-each>
    </xsl:for-each>
    <xsl:text> </xsl:text>
    <xsl:for-each select="norefs">
    <xsl:apply-templates/>
    </xsl:for-each>
    <xsl:text> </xsl:text>
    <xsl:for-each select="ti">
    <xsl:apply-templates/>
    </xsl:for-each>
    <xsl:text> </xsl:text>
    <xsl:for-each select="abs">
    <xsl:apply-templates/>
    </xsl:for-each>
    <xsl:text> </xsl:text>
    </xsl:for-each>
    John Larson, Sep 27, 2008
    #1
    1. Advertising

  2. Re: [Newbie] Output something using XSLT even if an element is missingin some documents?

    John Larson wrote:
    > Hi All,
    >
    > I am some information from INSPEC database records in XML to build a
    > relational database of my own. I am currently trying to extract information
    > by doing an XSLT transform of the XML files into a tab-separated text file
    > that I want to import into the database. I have run into the following
    > problem: in some documents there are missing elements, for instance the
    > volume and issue number of an article is not there (i.e. it is defined in
    > the DTD, but the element that contains these values happen not to be
    > included in some documents). This causes a problem because it messes up my
    > columns as all the rest of the elements I am extracting move left and thus
    > are placed in wrong columns.
    >
    > My question is: is there some way in XSLT output a value like "empty" or
    > "N/A" when some elements are missing?
    >


    For your inspiration: here an example stylesheet which is properly transforming XML documents into tab-separated text files: http://tinyurl.com/3zf2bo

    Hope this helps, Hermann
    Hermann Peifer, Sep 27, 2008
    #2
    1. Advertising

  3. John Larson

    John Larson Guest

    "Hermann Peifer" <> wrote in message
    news:...
    > For your inspiration: here an example stylesheet which is properly
    > transforming XML documents into tab-separated text files:
    > http://tinyurl.com/3zf2bo
    >
    > Hope this helps, Hermann


    Thanks Herman! I have now tried to construct a new XSLT based on your
    example (see the full text at the end). I think I have got it almost right,
    but when I try to run it in Xalan against my XML files I get the following
    exception:

    file:///data/disk21/tab-output.xslt; Line #71; Column #79; XSLT Error
    (javax.xml.transform.TransformerConfigurationException):
    javax.xml.transform.TransformerException: org.xml.sax.SAXParseException:
    Open quote is expected for attribute "select" associated with an element
    type "xsl:value-of".
    Exception in thread "main" java.lang.RuntimeException:
    javax.xml.transform.TransformerException: org.xml.sax.SAXParseException:
    Open quote is expected for attribute "select" associated with an element
    type "xsl:value-of".
    at org.apache.xalan.xslt.Process.doExit(Process.java:1153)
    at org.apache.xalan.xslt.Process.main(Process.java:1126)

    As far as I can see it does not like my qoutes, but they are exactly like
    yours. I run Xalan on a Linux server. The XSLT file is saved in Unix file
    format and ANSI encoding using TextPad, and then copied as binary to the
    server.

    Any ideas how to fix this?

    Thanks again - John

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

    <!-- Stylesheet inspired by one by Hermann Peifer, EEA, March 2008 -->

    <!-- Variable definition for tab delimited output -->
    <xsl:variable name="newline" select="'
    '"/>
    <xsl:variable name="tab" select="' '"/>


    <xsl:eek:utput method="text" encoding="UTF-8"/>


    <xsl:template match="/">

    <!-- Write out field names -->
    <xsl:text>accn</xsl:text> <xsl:value-of select="$tab"/>
    <xsl:text>abgn</xsl:text> <xsl:value-of select="$tab"/>
    <xsl:text>newrt</xsl:text> <xsl:value-of select="$tab"/>
    <xsl:text>rtname</xsl:text> <xsl:value-of select="$tab"/>
    <xsl:text>jt</xsl:text> <xsl:value-of select="$tab"/>
    <xsl:text>ajt</xsl:text> <xsl:value-of select="$tab"/>
    <xsl:text>vol</xsl:text> <xsl:value-of select="$tab"/>
    <xsl:text>ino</xsl:text> <xsl:value-of select="$tab"/>
    <xsl:text>voliss</xsl:text> <xsl:value-of select="$tab"/>
    <xsl:text>yr</xsl:text> <xsl:value-of select="$newline"/>

    <xsl:apply-templates select="inspec/article"/>

    </xsl:template>

    <!-- Loop through each field -->
    <xsl:template match="article">
    <xsl:value-of select="inspec/article/contg/accn"/> <xsl:value-of
    select="$tab"/>
    <xsl:value-of select="inspec/article/contg/abng"/> <xsl:value-of
    select="$tab"/>
    <xsl:value-of select="inspec/article/contg/rtypg/newrt"/> <xsl:value-of
    select="$tab"/>
    <xsl:value-of select="inspec/article/contg/rtypg/rtng/rtname"/>
    <xsl:value-of select="$tab"/>
    <xsl:value-of select="inspec/article/bibliog/jrefg/jrog/jt"/>
    <xsl:value-of select="$tab"/>
    <xsl:value-of select="inspec/article/bibliog/jrefg/jrog/ajt"/>
    <xsl:value-of select="$tab"/>
    <xsl:value-of select="inspec/article/bibliog/jrefg/jrog/vid/vol"/>
    <xsl:value-of select="$tab"/>
    <xsl:value-of select="inspec/article/bibliog/jrefg/jrog/vid/ino"/>
    <xsl:value-of select="$tab"/>
    <xsl:value-of select="inspec/article/bibliog/jrefg/jrog/vid/voliss"/>
    <xsl:value-of select="$tab"/>
    <xsl:value-of select="inspec/article/contg/crt/yr"/> <xsl:value-of
    select=$newline"/>
    </xsl:template>

    </xsl:stylesheet>
    John Larson, Sep 27, 2008
    #3
  4. John Larson

    John Larson Guest

    I wrote:
    > As far as I can see it does not like my qoutes, but they are exactly like
    > yours. I run Xalan on a Linux server. The XSLT file is saved in Unix file
    > format and ANSI encoding using TextPad, and then copied as binary to the
    > server.
    >
    > Any ideas how to fix this?


    My apologies - there was a quote missing right at the end by newline. After
    fixing this the tranformation now runs. Sadly the output only contains the
    field name and a lot of tabs - none of the content is printed out (and there
    is content in some elements that should be there).

    The root element of my XML files is "inspec" and each file contains an
    number of articles, which is next level down in the tree. The data I want to
    extract is in child elements under article. An example XPATH is
    "inspec/article/bibliog/jrefg/jrog/vid/vol". Am I somehow pointing
    incorrectly or not calling the select correctly or ?

    Thanks - John

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

    <!-- Stylesheet inspired by one by Hermann Peifer, EEA, March 2008 -->

    <!-- Variable definition for tab delimited output -->
    <xsl:variable name="newline" select="'
    '"/>
    <xsl:variable name="tab" select="' '"/>


    <xsl:eek:utput method="text" encoding="UTF-8"/>


    <xsl:template match="/">

    <!-- Write out field names -->
    <xsl:text>accn</xsl:text> <xsl:value-of select="$tab"/>
    <xsl:text>abgn</xsl:text> <xsl:value-of select="$tab"/>
    <xsl:text>newrt</xsl:text> <xsl:value-of select="$tab"/>
    <xsl:text>rtname</xsl:text> <xsl:value-of select="$tab"/>
    <xsl:text>jt</xsl:text> <xsl:value-of select="$tab"/>
    <xsl:text>ajt</xsl:text> <xsl:value-of select="$tab"/>
    <xsl:text>vol</xsl:text> <xsl:value-of select="$tab"/>
    <xsl:text>ino</xsl:text> <xsl:value-of select="$tab"/>
    <xsl:text>voliss</xsl:text> <xsl:value-of select="$tab"/>
    <xsl:text>yr</xsl:text> <xsl:value-of select="$newline"/>

    <xsl:apply-templates select="inspec/article"/>

    </xsl:template>

    <!-- Loop through each field -->
    <xsl:template match="article">
    <xsl:value-of select="inspec/article/contg/accn"/> <xsl:value-of
    select="$tab"/>
    <xsl:value-of select="inspec/article/contg/abng"/> <xsl:value-of
    select="$tab"/>
    <xsl:value-of select="inspec/article/contg/rtypg/newrt"/> <xsl:value-of
    select="$tab"/>
    <xsl:value-of select="inspec/article/contg/rtypg/rtng/rtname"/>
    <xsl:value-of select="$tab"/>
    <xsl:value-of select="inspec/article/bibliog/jrefg/jrog/jt"/> <xsl:value-of
    select="$tab"/>
    <xsl:value-of select="inspec/article/bibliog/jrefg/jrog/ajt"/>
    <xsl:value-of select="$tab"/>
    <xsl:value-of select="inspec/article/bibliog/jrefg/jrog/vid/vol"/>
    <xsl:value-of select="$tab"/>
    <xsl:value-of select="inspec/article/bibliog/jrefg/jrog/vid/ino"/>
    <xsl:value-of select="$tab"/>
    <xsl:value-of select="inspec/article/bibliog/jrefg/jrog/vid/voliss"/>
    <xsl:value-of select="$tab"/>
    <xsl:value-of select="inspec/article/contg/crt/yr"/> <xsl:value-of
    select="$newline"/>
    </xsl:template>

    </xsl:stylesheet>
    John Larson, Sep 27, 2008
    #4
  5. John Larson

    John Larson Guest

    "John Larson" wrote:
    > My apologies - there was a quote missing right at the end by newline.
    > After fixing this the tranformation now runs. Sadly the output only
    > contains the field name and a lot of tabs - none of the content is printed
    > out (and there is content in some elements that should be there).
    >
    > The root element of my XML files is "inspec" and each file contains an
    > number of articles, which is next level down in the tree. The data I want
    > to extract is in child elements under article. An example XPATH is
    > "inspec/article/bibliog/jrefg/jrog/vid/vol". Am I somehow pointing
    > incorrectly or not calling the select correctly or ?
    >
    > Thanks - John


    After a lot of trial and error I figured out that I needed to shorten my
    XPATHs in the value of select statements (e.g. from <xsl:value-of
    select="inspec/article/contg/accn"/> to <xsl:value-of
    select="contg/accn"/>). It now works beautifully - thanks to Hermann for
    pointing to this solution.

    Best

    - John
    John Larson, Sep 27, 2008
    #5
  6. John Larson

    John Larson Guest

    "John Larson" wrote:
    > My apologies - there was a quote missing right at the end by newline.
    > After fixing this the tranformation now runs. Sadly the output only
    > contains the field name and a lot of tabs - none of the content is printed
    > out (and there is content in some elements that should be there).
    >
    > The root element of my XML files is "inspec" and each file contains an
    > number of articles, which is next level down in the tree. The data I want
    > to extract is in child elements under article. An example XPATH is
    > "inspec/article/bibliog/jrefg/jrog/vid/vol". Am I somehow pointing
    > incorrectly or not calling the select correctly or ?
    >
    > Thanks - John


    After a lot of trial and error I figured out that I needed to shorten my
    XPATHs in the value of select statements (e.g. from <xsl:value-of
    select="inspec/article/contg/accn"/> to <xsl:value-of
    select="contg/accn"/>). It now works beautifully - thanks to Hermann for
    pointing to this solution.

    Best

    - John
    John Larson, Sep 27, 2008
    #6
  7. Re: [Newbie] Output something using XSLT even if an element is missingin some documents?

    John Larson wrote:
    > "John Larson" wrote:
    >> My apologies - there was a quote missing right at the end by newline.
    >> After fixing this the tranformation now runs. Sadly the output only
    >> contains the field name and a lot of tabs - none of the content is printed
    >> out (and there is content in some elements that should be there).
    >>
    >> The root element of my XML files is "inspec" and each file contains an
    >> number of articles, which is next level down in the tree. The data I want
    >> to extract is in child elements under article. An example XPATH is
    >> "inspec/article/bibliog/jrefg/jrog/vid/vol". Am I somehow pointing
    >> incorrectly or not calling the select correctly or ?
    >>
    >> Thanks - John

    >
    > After a lot of trial and error I figured out that I needed to shorten my
    > XPATHs in the value of select statements (e.g. from <xsl:value-of
    > select="inspec/article/contg/accn"/> to <xsl:value-of
    > select="contg/accn"/>). It now works beautifully - thanks to Hermann for
    > pointing to this solution.
    >
    > Best
    >
    > - John
    >
    >
    >


    Good to hear that you got it right.

    You could add a leading slash to your select attribute:
    <xsl:apply-templates select="/inspec/article"/>

    Then, the XSLT processor will only search for inspec/article elements, which are immediately under the root element, and not somewhere in the middle of the XML structure (which might not occur in your XML document, but being as specific as possible is always a good idea, as it also saves processing time).

    I assume that each article has max. 1 accn, abgn, etc. elements. If not: you will only get the value of the first one.

    Hermann
    Hermann Peifer, Sep 28, 2008
    #7
    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. Stan Goodman

    Even older fart, even newer newbie

    Stan Goodman, Jul 3, 2003, in forum: Java
    Replies:
    11
    Views:
    676
    Stan Goodman
    Jul 4, 2003
  2. mjarends
    Replies:
    7
    Views:
    1,255
    Thomas Meinike
    Feb 14, 2006
  3. Replies:
    1
    Views:
    470
    Juan T. Llibre
    Oct 18, 2006
  4. Replies:
    4
    Views:
    553
    delirio
    Jun 26, 2007
  5. B. Angell
    Replies:
    4
    Views:
    74
    William James
    Aug 16, 2005
Loading...

Share This Page