Search code examples
pythonxmlxsltsaxonsaxon-c

saxonc's transform_to_file() produces no output file when supplying xdm_node


This seems to be answered by @alinaOS in SaxonC 11.1 transform_to_file Produces No Output File but doesn't answer their question. It might be more suitable here.

My workaround doesn't work either (see saxonc's transform_to_file(), executed in a loop, doesn't transform but gives non-sensical errors or partial output)

I'm trying to run saxon-c's transform_to_file() with an xml string as input (not a file).

xsltproc.transform_to_file(xdm_node=xml_doc,
                           stylesheet_file="transformer.xsl",
                           output_file=transformedfile)

I get no errors but also no output file.

My transformation stylesheet file contains:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/">
        <cities>
            <xsl:for-each select="cities/country">
                <city name="{@capital}" isCapital="true"/>
            </xsl:for-each>
        </cities>
    </xsl:template>
</xsl:stylesheet>

My python code:

import os
import xml.etree.ElementTree as ET
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>
    '''
    parentroot = ET.fromstring(source_XML)
    children = list(parentroot)

    cnt = 0
    for child in children:
        cnt = cnt + 1
        childroot = ET.Element("cities")
        childroot.append(child)
        temp_tree = ET.ElementTree(childroot)
        # has to be unicode for proc.parse_xml()
        xml_str = ET.tostring(temp_tree.getroot(), encoding='unicode', method='xml')
        transformedfile = f"output_{cnt}.xml"
        try:
            with PySaxonProcessor(license=False) as proc:
                proc.set_cwd(os.getcwd())
                xsltproc = proc.new_xslt30_processor()


                xml_doc = proc.parse_xml(xml_text=xml_str)
                xsltproc.xsltproc.transform_to_file(xdm_node=xml_doc,
                                           stylesheet_file="transformer.xsl",
                                           output_file=transformedfile)
                print(f"ended. But where is {str(proc.cwd)}\\{transformedfile}?")
        except Exception as e:
            print(f"exception occured: {e}")

if __name__ == "__main__":
    main()

Solution

  • Apply_templates_returning_file works:

    import os
    import xml.etree.ElementTree as ET
    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>
        '''
        parentroot = ET.fromstring(source_XML)
        children = list(parentroot)
    
        cnt = 0
        for child in children:
            cnt = cnt + 1
            childroot = ET.Element("cities")
            childroot.append(child)
            temp_tree = ET.ElementTree(childroot)
            # has to be unicode for proc.parse_xml()
            xml_str = ET.tostring(temp_tree.getroot(), encoding='unicode', method='xml')
            transformedfile = f"output_fromxdm_{cnt}.xml"
            try:
                with PySaxonProcessor(license=False) as proc:
                    proc.set_cwd(os.getcwd())
                    xsltproc = proc.new_xslt30_processor()
                    xslt30_transformer = xsltproc.compile_stylesheet(stylesheet_file="transformer.xsl")
    
                    xml_doc = proc.parse_xml(xml_text=xml_str)
                    # set_initial_match_selection belongs to xslt30_transformer, not xsltproc or proc!
                    xslt30_transformer.set_initial_match_selection(xdm_value=xml_doc)
                    xslt30_transformer.apply_templates_returning_file(xdm_node=xml_doc,
                                                                      output_file=transformedfile)
    
                    print(f"{transformedfile} has been created.")
            except Exception as e:
                print(f"exception occured: {e}")
    
    if __name__ == "__main__":
        main()