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

J

John Larson

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>
 
H

Hermann Peifer

John said:
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
 
J

John Larson

Hermann Peifer said:
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>
 
J

John Larson

I said:
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>
 
J

John Larson

John Larson said:
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
 
J

John Larson

John Larson said:
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
 
H

Hermann Peifer

John said:
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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,008
Latest member
HaroldDark

Latest Threads

Top