Home > front end >  XPDY0002 The context item for axis step $nodeset is absent
XPDY0002 The context item for axis step $nodeset is absent

Time:06-06

I'm getting the XPDY0002 context item is absent error. I've seen the other questions regarding this but I don't really understand the answers nor do I see how to apply them to my python code.

The problem seems to occur in this strange xslt 1.0 setup where I have a node-set, identity transform and regular match="/" present. My example is a distilled version of a much more complex stylesheet that I didn't write. But the point is that it transforms with Oxygen running Saxon-HE 9.9.1.7, but with my python saxonc I get an error.

I've tried set_global_context_item() but it just hangs.

My error in pycharm

Error at char 0 in expression in xsl:for-each/@select on line 19 column 55 of stylesheet.xsl:
  XPDY0002  The context item for axis step $sortedInput_nodeset/country is absent
  In template rule with match="/" on line 18 of stylesheet.xsl

My python code

import os
from saxonpy import PySaxonProcessor

def main():

    proc = PySaxonProcessor(license=False)
    proc.set_cwd(os.getcwd())
    xsltproc = proc.new_xslt30_processor()
    xslt30_transformer = xsltproc.compile_stylesheet(stylesheet_file="stylesheet.xsl")
    xslt30_transformer.apply_templates_returning_file(source_file="raw.xml",
                                                      output_file="result.xml")

if __name__ == "__main__":
    main()

The problem still occurs when transforming from xdm_node to file:

    xslt30_transformer.set_initial_match_selection(xdm_value=xml_doc)
    xslt30_transformer.apply_templates_returning_file(xdm_node=xml_doc,
                                                      output_file=path_to_output_file)

My xslt stylesheet

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

    <xsl:variable name="sortedInput_RTF">
        <xsl:apply-templates select="/data/country">
            <xsl:sort select="@name" order="descending"/>
        </xsl:apply-templates>
    </xsl:variable>
    <xsl:variable name="sortedInput_nodeset" select="exsl:node-set($sortedInput_RTF)"/>
    
    <xsl:template match="node() | @*">
        <xsl:copy>
            <xsl:apply-templates select="node() | @*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="/">
        <xsl:for-each select="$sortedInput_nodeset/country">
            <xsl:value-of select="@capital"/>
        </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>

My source xml

<?xml version="1.0" encoding="UTF-8"?>
<data>
    <country name="Denmark" capital="Copenhagen"/>
    <country name="Germany" capital="Berlin"/>
    <country name="France" capital="Paris"/>
</data>

My output in using Saxon-HE 9.9.1.7 in Oxygen

BerlinParisCopenhagen

Follow-up

This stylesheet works (proving the problem is not exsl):

    <xsl:template match="/">
        <xsl:variable name="sortedInput_RTF">
            <root>
                <country capital="a"/>
                <country capital="b"/>
                <country capital="c"/>
            </root>
        </xsl:variable>
        <xsl:variable name="sortedInput_nodeset" select="exsl:node-set($sortedInput_RTF)"/>
        <xsl:for-each select="$sortedInput_nodeset/root/country">
            <xsl:value-of select="@capital"/>
        </xsl:for-each>
    </xsl:template>

CodePudding user response:

Although this stylesheet says version="1.0", you are running it with an XSLT 3.0 processor, so the 3.0 rules apply.

In 3.0, there's a distinction between the "initial match selection" (the node(s) that determine which template rule fires first), and the "global context item" (the context item for evaluating global variables). I think the failure is because the global context item is absent.

You say "I've tried set_global_context_item() but it just hangs". Well, you're doing the right thing and it shouldn't hang, so you need to follow that path and find out what's going wrong.

Note that the "transform_to_XXX" methods combine the functions of setting the global context item, setting the initial match selection, and invoking the transformation using "apply_templates".

CodePudding user response:

this is the complete code, following @Michael Kay's accepted answer... Works for both text to file and file to file.

import os
from saxonpy import PySaxonProcessor

def main():
    print('starting code...')
    source_XML = '''
        <data>
            <country name="Denmark" capital="Copenhagen"/>
            <country name="Germany" capital="Berlin"/>
            <country name="France" capital="Paris"/>
        </data>
    '''

    proc = PySaxonProcessor(license=False)
    proc.set_cwd(os.getcwd())
    xsltproc = proc.new_xslt30_processor()
    xslt30_transformer = xsltproc.compile_stylesheet(stylesheet_file="stylesheet.xsl")

    # FROM TEXT TO FILE
    xml_doc = proc.parse_xml(xml_text=source_XML)
    xslt30_transformer.set_global_context_item(xdm_item=xml_doc)
    xslt30_transformer.set_initial_match_selection(xdm_value=xml_doc)
    xslt30_transformer.apply_templates_returning_file(xdm_node=xml_doc,
                                                      output_file="result.txt")

    # FROM FILE TO FILE
    # xslt30_transformer.set_global_context_item(file_name="raw.xml")
    # xslt30_transformer.set_initial_match_selection(file_name="raw.xml")
    # xslt30_transformer.apply_templates_returning_file(source_file="raw.xml",
    #                                                   output_file="result.txt")

if __name__ == "__main__":
    main()
  • Related