0

I have an XML file and need to add a new element that contains values from a sibling element with XSLT. What I have is this:

<?xml version="1.0" encoding="UTF-8"?>
<collection
    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"
    xmlns="http://www.loc.gov/MARC21/slim">
<record>
        <datafield tag="035" ind1=" " ind2=" ">
            <subfield code="a">(OCoLC)ocm02255682</subfield>
        </datafield>
      <datafield tag="959" ind1=" " ind2=" ">
         <subfield code="a">(MILdb)299946</subfield>
      </datafield>
        <datafield tag="959" ind1=" " ind2=" ">
            <subfield code="a">(UIUdb)3899758</subfield>
        </datafield>
</record>

And what I need is this:

<?xml version="1.0" encoding="UTF-8"?>
<collection
    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"
    xmlns="http://www.loc.gov/MARC21/slim">
<record>
        <datafield tag="035" ind1=" " ind2=" ">
            <subfield code="a">(OCoLC)ocm02255682</subfield>
        </datafield>
        <datafield tag="035" ind1=" " ind2=" ">
            <subfield code="z">(UIU)Voyager3899758</subfield>
        </datafield>
      <datafield tag="959" ind1=" " ind2=" ">
         <subfield code="a">(MILdb)299946</subfield>
      </datafield>
        <datafield tag="959" ind1=" " ind2=" ">
            <subfield code="a">(UIUdb)3899758</subfield>
        </datafield>
</record>

I've been working at it for a few hours with no meaningful output. Any help would be appreciated.

Here is what I have so far. This is the first XSLT I've tried to write, and I not sure if I'm on the right track. The output has the new field (but with namespaces for some reason), and does not include the value from the 959 subfield a element.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:marc="http://www.loc.gov/MARC21/slim"
    version="1.0">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
   

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="marc:record">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
            <datafield tag="035" ind1=" " ind2=" ">
                <subfield code="z">(UIU)Voyager
                     <xsl:value-of select="marc:datafield[@tag=959]/marc:subfield[@code='a']"/>
                </subfield>
            </datafield>
        </xsl:copy>
    </xsl:template> 
                
</xsl:stylesheet>
1
  • Could you add whatever xsl you have so far? Commented Aug 11, 2020 at 8:04

1 Answer 1

1

AFAICT, you want to do:

XSLT 1.0

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

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="marc:record">
    <xsl:copy>
        <xsl:apply-templates/>
        <datafield tag="035" ind1=" " ind2=" ">
            <subfield code="z">
                <xsl:text>(UIU)Voyager</xsl:text>
                <xsl:value-of select="substring-after(marc:datafield[@tag=959]/marc:subfield[@code='a'], ')')"/>
            </subfield>
        </datafield>
    </xsl:copy>
</xsl:template> 

</xsl:stylesheet>

Added:

To create the new element only when a datafield whose tag value is 959 and has a subfield that starts with "(UIUdb)" exists, change the 2nd template to:

<xsl:template match="marc:datafield[@tag=959][starts-with(marc:subfield, '(UIUdb)')]">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
    <datafield tag="035" ind1=" " ind2=" ">
        <subfield code="z">
            <xsl:text>(UIU)Voyager</xsl:text>
            <xsl:value-of select="substring-after(marc:subfield, '(UIUdb)')"/>
        </subfield>
    </datafield>
</xsl:template> 
Sign up to request clarification or add additional context in comments.

10 Comments

Thank you, that's it! The new datafield element still has the marc namespace, but I can edit that out easily enough.
Not sure what you mean by "new datafield element still has the marc namespace". All datafield elements are in the same namespace. There should be no need to edit anything out - see the demo here: xsltfiddle.liberty-development.net/pNmCzt4
It gives me <datafield xmlns:marc="loc.gov/MARC21/slim" tag="035" ind1=" " ind2=" "> where I was expecting <datafield tag="035" ind1=" " ind2=" ">. I don't think it affects anything, but none of the other datafields have that within the element tag.
Are you using the exact stylesheet I have posted, with the exclude-result-prefixes="marc" atttribute?
There must be some difference. You can see that Saxon 9.8 does NOT return the result you claim: xsltfiddle.liberty-development.net/pNmCzt4/1
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.