user3673154
user3673154

Reputation: 13

Selecting and concatenating specific string using XSLT

I have thousands of MarcXML records and I need to select and concatenate specific strings from each record. Unfortunately I seem to only be able to have my XSLT table pick up the same strings from the first record for each MarcXML record in the file.

The MarcXML records I have are like this:

<?xml version="1.0" encoding="UTF-8" ?> 
<marc:collection xmlns:marc="http://www.loc.gov/MARC21/slim" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd">
<marc:record>
<marc:leader>01195cam a2200301 a 4500</marc:leader> 
<marc:datafield tag="100" ind1="1" ind2="">
<marc:subfield code="a">Bache, Franklin,</marc:subfield> 
<marc:subfield code="d">1792-1864.</marc:subfield> 
</marc:datafield>
<marc:datafield tag="245" ind1="1" ind2="3">
<marc:subfield code="a">An obituary notice of Thomas T. Hewson, M. D. :</marc:subfield> 
<marc:subfield code="h">[electronic resource]</marc:subfield> 
<marc:subfield code="b">late president of the Philadelphia College of Physicians
</marc:subfield> 
<marc:subfield code="c">by Franklin Bache ; read before the college, November 6, 1849 ; and published by its direction.</marc:subfield> 
</marc:datafield>
<marc:datafield tag="260" ind1="" ind2="">
<marc:subfield code="a">Philadelphia :</marc:subfield> 
<marc:subfield code="b">Geddes,</marc:subfield> 
<marc:subfield code="c">1850.</marc:subfield> 
</marc:datafield>
</marc:record>

<marc:record>
<marc:leader>01429cam a2200325 a 4500</marc:leader> 
</marc:datafield>
<marc:datafield tag="110" ind1="2" ind2="">
<marc:subfield code="a">American Public Health Association.</marc:subfield> 
<marc:subfield code="b">Committee on the Prevention of Venereal Diseases.</marc:subfield> 
</marc:datafield>
<marc:datafield tag="245" ind1="1" ind2="0">
<marc:subfield code="a">Report of the Committee on the Prevention of Venereal Diseases :</marc:subfield> 
<marc:subfield code="h">[electronic resource]</marc:subfield> 
<marc:subfield code="b">presented at the eighth annual meeting of the American Public Health Association, New Orleans, La., Nov. 7-10, 1880.</marc:subfield> 
</marc:datafield>
<marc:datafield tag="260" ind1="" ind2="">
<marc:subfield code="a">Boston :</marc:subfield> 
<marc:subfield code="b">Franklin,</marc:subfield> 
<marc:subfield code="c">1881.</marc:subfield> 
</marc:datafield>
</marc:record>

My XSLT is:

  <?xml version="1.0" encoding="UTF-8" ?> 
- <xsl:stylesheet version="1.0" xmlns:marc="http://www.loc.gov/MARC21/slim" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="marc">
  <xsl:output method="text" encoding="UTF-8" indent="no" /> 
- <xsl:template match="marc:collection">
- <xsl:for-each select="marc:record">
- <xsl:choose>
- <xsl:when test="contains(//marc:leader, 'cam')">
  <xsl:call-template name="Title" /> 
  <xsl:call-template name="Date" /> 
  </xsl:when>
  </xsl:choose>
  </xsl:for-each>
  </xsl:template>
- <xsl:template name="Title">
  <xsl:variable name="short" select="//marc:datafield[@tag=245]/marc:subfield[@code='a']" /> 
  <xsl:value-of select="substring($short,1,20)" /> 
  </xsl:template>
- <xsl:template name="Date">
  <xsl:variable name="dd" select="//marc:datafield[@tag=260]/marc:subfield[@code='c']" /> 
  <xsl:value-of select="substring($dd,1,4)" /> 
  </xsl:template>
  </xsl:stylesheet>

I wanted the output to be something like:

An obituary notice of1850
Report of the Committ1881

But instead I get twice the first string. I've tried not using <xsl:for-each> but the result was the same. The only way I can parse each record is by using a template but this won't allow me to choose specific strings. Can anyone help me?

Upvotes: 1

Views: 199

Answers (1)

Daniel Haley
Daniel Haley

Reputation: 52878

The problem you are having is context. There's no need to use // at the beginning of your XPaths. That is querying the entire document. In XSLT 1.0, you only get the first result. That's why you're seeing the first string twice.

Here's an updated version of your stylesheet. I've removed the // and changed the "Title" substring() (to get the output in your example). I've also added a line break (&#xA;).

Updated XSLT 1.0

<xsl:stylesheet version="1.0" xmlns:marc="http://www.loc.gov/MARC21/slim" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="marc">
    <xsl:output method="text" encoding="UTF-8" indent="no"/>
    <xsl:template match="marc:collection">
        <xsl:for-each select="marc:record">
            <xsl:choose>
                <xsl:when test="contains(marc:leader, 'cam')">
                    <xsl:call-template name="Title"/>
                    <xsl:call-template name="Date"/>
                    <xsl:text>&#xA;</xsl:text>
                </xsl:when>
            </xsl:choose>
        </xsl:for-each>
    </xsl:template>

    <xsl:template name="Title">
        <xsl:variable name="short" select="marc:datafield[@tag=245]/marc:subfield[@code='a']"/>
        <xsl:value-of select="substring($short,1,21)"/>
    </xsl:template>

    <xsl:template name="Date">
        <xsl:variable name="dd" select="marc:datafield[@tag=260]/marc:subfield[@code='c']"/>
        <xsl:value-of select="substring($dd,1,4)"/>
    </xsl:template>

</xsl:stylesheet>

You could get rid of the extra templates though. This is how I would do it:

XSLT 1.0

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:marc="http://www.loc.gov/MARC21/slim"
    exclude-result-prefixes="marc">
    <xsl:output method="text" encoding="UTF-8"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/*">
        <xsl:apply-templates select="marc:record[contains(marc:leader, 'cam')]"/>
    </xsl:template>

    <xsl:template match="marc:record">
        <xsl:value-of select="substring(marc:datafield[@tag=245]/marc:subfield[@code='a'],1,21)"/>
        <xsl:value-of select="substring(marc:datafield[@tag=260]/marc:subfield[@code='c'],1,4)"/>
        <xsl:text>&#xA;</xsl:text>        
    </xsl:template>

</xsl:stylesheet>

Both of these will give you the following output:

An obituary notice of1850
Report of the Committ1881

Upvotes: 2

Related Questions