0

Recently I started using a flat file manager called Cardbox to maintain lists of my film and music collections. Cardbox outputs records in both CSV and XML formats and I use the latter to create web pages so that I can easily proofread my work. I would like to convert it to a form of XML that uses the field names as elements rather than as attributes of a common element and eliminates the <x>...</x> tags. The software will accept an XSLT transform to do this.

Here is an example of what I would like to do.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<data xmlns="http://www.cardbox.com/cardbox3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.cardbox.com/cardbox3 http://www.cardbox.com/schemas/cardbox3.xsd">
<fields>
 <field name="DIRECTOR" id="1"/>
 <field name="TITLE" id="2"/>
 <field name="PERFORMERS" id="3"/>
 <field name="LABEL" id="4"/>
 <field name="YEAR" id="5"/>
 <field name="FORMAT" id="6"/>
</fields>
<records count="407" written="2021-03-03T16:38:11-06:00">
<record>
<f id="1"><x>Akerman, Chantal.</x></f>
<f id="2"><x>Jeanne Dielman: 23, Quai du Commerce, 1080 Bruxelles.</x></f>
<f id="3"><x>Delphine Seyrig.</x></f>
<f id="4"><x>Criterion Collection 484</x></f>
<f id="5"><x>1975</x></f>
<f id="6"><x>DVD</x></f>
</record>
...
</records>
</data>

Change to:

<record>
<DIRECTOR>Akerman, Chantal.</DIRECTOR>
<TITLE>Jeanne Dielman: 23, Quai du Commerce, 1080 Bruxelles.</TITLE>
<PERFORMERS>Delphine Seyrig.</PERFORMERS>
<LABEL>Criterion Collection 484</LABEL>
<YEAR>1975</YEAR>
<FORMAT>DVD</FORMAT>
</record>

I have created an XSL file based on models I have found in Michael Kay's 2008 Programmer's Reference book (pp. 74-77), in questions about XML to XML conversion on this list, and in a MARCXML to Dublin Core XML stylesheet at the Library of Congress (https://www.loc.gov/standards/marcxml/xslt/MARC21slim2RDFDC.xsl)

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

<xsl:output method="xml" indent="yes"/>

 <xsl:template match="/data/records">
   <records>
      <xsl:apply-templates select="record"/>
   </records>
 </xsl:template>

 <xsl:template match="record">
   <record>
    <xsl:for-each select="f[@id=1]/x">
          <director>
            <xsl:value-of select="."/>
          </director>
    </xsl:for-each>

    <xsl:for-each select="f[@id=2]/x">
          <title>
            <xsl:value-of select="."/>
          </title>
    </xsl:for-each>

    <xsl:for-each select="f[@id=3]/x">
          <performers>
            <xsl:value-of select="."/>
          </performers>
    </xsl:for-each>

    <xsl:for-each select="f[@id=4]/x">
          <label>
            <xsl:value-of select="."/>
          </label>
    </xsl:for-each>

    <xsl:for-each select="f[@id=5]/x">
          <year>
            <xsl:value-of select="."/>
          </year>
    </xsl:for-each>

    <xsl:for-each select="f[@id=6]/x">
          <format>
            <xsl:value-of select="."/>
          </format>
    </xsl:for-each>
   </record>
 </xsl:template>
</xsl:stylesheet>

What I get back from running this is the plain text of my database records, each field on a separate line. There is no XML encoding.

Akerman, Chantal.
Jeanne Dielman: 23, Quai du Commerce, 1080 Bruxelles.
Delphine Seyrig.
Criterion Collection 484
1975
DVD

What am I missing to create the change in XML encoding that I am trying to achieve?

1 Answers1

0

What am I missing

You are missing the fact that your XML puts its elements in a namespace. As a result, your templates do not match anything, and the entire output is produced by the built-in template rules. See https://stackoverflow.com/a/34762628/3016153 how to handle this.

The other thing is that there is no need to list each field and its name explicitly in the stylesheet. You can construct a more dynamic stylesheet that can handle any number of fields, with any names (as long as the names are also valid element names):

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:cb3="http://www.cardbox.com/cardbox3" 
exclude-result-prefixes="cb3">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="field" match="cb3:field" use="@id"/>

<xsl:template match="/cb3:data">
    <records>
        <xsl:for-each select="cb3:records/cb3:record">
            <record>
                <xsl:for-each select="cb3:f">
                    <xsl:element name="{key('field', @id)/@name}">
                        <xsl:value-of select="cb3:x"/>
                    </xsl:element>
                </xsl:for-each>
            </record>
        </xsl:for-each>
    </records>
</xsl:template>

</xsl:stylesheet>

Note the use of a key to lookup the element's name from the fields branch.

michael.hor257k
  • 113,275
  • 6
  • 33
  • 51