zneak
zneak

Reputation: 138051

How do I iterate over every element of a specific name in a document()?

I have two input files:

<!-- index.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<ns:index xmlns:ns="http://localhost/">
    <ns:document>test.xml</ns:document>
</ns:index>

 

<!-- test.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<ns:test xmlns="http://www.w3.org/1999/xhtml" xmlns:ns="http://localhost/">
    <div><figure id="fig-1-1">Figure 1-1</figure></div>
    <figure id="fig-1-2">Figure 1-2</figure>
</ns:test>

Using an XSLT stylesheet, I'm trying to create a figure index that would look like this:

<?xml version="1.0" encoding="UTF-8"?>
<ns:figures xmlns="http://www.w3.org/1999/xhtml" xmlns:ns="http://localhost/">
    <figure id="fig-1-1">test.xml</figure>
    <figure id="fig-1-2">test.xml</figure>
</ns:figures>

It seemed to me that I should be able to use the document() function for this purpose. I tried using the following stylesheet, and the (most likely ancient version of) xsltproc tool that comes preinstalled on macOS High Sierra systems:

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

<xsl:template match="/ns:index">
    <ns:figures>
        <xsl:for-each select="ns:document">
            <xsl:variable name="file-path"><xsl:value-of select="text()"/></xsl:variable>
            <xsl:for-each select="document($file-path)//figure">
                <ns:figure>
                    <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
                    <xsl:value-of select="$file-path"/>
                </ns:figure>
            </xsl:for-each>
        </xsl:for-each>
    </ns:figures>
</xsl:template>

</xsl:stylesheet>

However, while I can confirm that for-each select="ns:document" is entered, and that document($file-path) does find the file (using the --load-trace option), the full expression document($file-path)//figure is always empty.

I can find examples of stylesheets that apparently work when you do this. Am I doing something wrong? What are my options here?

Upvotes: 1

Views: 24

Answers (1)

Mads Hansen
Mads Hansen

Reputation: 66723

Your <figure> elements are bound to the xhtml namespace.

Note that the figures element has the xhtml namespace declared without a namespace-prefix:

<ns:figures xmlns="http://www.w3.org/1999/xhtml" xmlns:ns="http://localhost/">

You have the xhtml namespace declared in your XSLT, but without a namespace-prefix. You must provide some prefix if you want to refer to elements from that namespace in XPath.

Change your XSLT to use a namespace-prefix for the xhtml namespace, and adjust your XPath to use it:

<xsl:stylesheet
    version="1.0"
    xmlns:xhtml="http://www.w3.org/1999/xhtml"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ns="http://localhost/">

<xsl:template match="/ns:index">
    <ns:figures>
        <xsl:for-each select="ns:document">
            <xsl:variable name="file-path"><xsl:value-of select="text()"/></xsl:variable>
            <xsl:for-each select="document($file-path)//xhtml:figure">
                <ns:figure>
                    <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
                    <xsl:value-of select="$file-path"/>
                </ns:figure>
            </xsl:for-each>
        </xsl:for-each>
    </ns:figures>
</xsl:template>

</xsl:stylesheet>

Upvotes: 2

Related Questions