Package: saxonpy
Welcome to Saxonpy!This's a python wheel package forSaxon, an XML processor from the Saxonica company. Saxon includes a range of tools for XML transformations, XML queries, and schema validations. For this release, we only include the support for the home edition or the open-source version.When to choose SaxonpyIf you need to useXSLT versions greater than 1.0like 2.0 and 3.0, then you may use Saxonpy.As of 2021, there are two great python packages already available:xmlandlxml. The Pythonxmlseems to be great if you just need to parse the xml documents whilelxmlseems to offer more options for processing xml files. Becauselxmluses libxslt, a C library for transforming xmls, it supports xslt version 1.0 only.InstallationpipinstallsaxonpyUsageI will make references to the Saxonica official documentation a lot from here because they list all the Python APIs with examples for some.Import all the modulesfromsaxonpyimport*Import specific modulesfromsaxonpyimportPySaxonProcessorNow, let's check what 6 other processors are available from Saxon by visiting theSaxonica's site. In the API section, you will find more info about what each processor does.Next, we will usePySaxonProcessorto check the Saxon version.fromsaxonpyimportPySaxonProcessorwithPySaxonProcessor(license=False)asproc:print(proc.version)It will print the version like below if your installation is successful.Saxon/C1.2.1runningwithSaxon-HE9.9.1.5CfromSaxonicaPleasenotethatlicense=Falseindicates the open-source version of Saxon.Example #1Let's parse a toy XML that was available from Saxonica source code.fromsaxonpyimportPySaxonProcessorwithPySaxonProcessor(license=False)asproc:xml="""\<out><person att1='value1' att2='value2'>text1</person><person>text2</person><person>text3</person></out>"""node=proc.parse_xml(xml_text=xml)print("node.node_kind="+node.node_kind_str)print("node.size="+str(node.size))outNode=node.childrenprint("len of children="+str(len(node.children)))print('element name='+outNode[0].name)children=outNode[0].childrenprint(*children,sep=', ')attrs=children[1].attributesiflen(attrs)==2:print(attrs[1].string_value)In the output, we will get this.node.node_kind=document
node.size=1lenofchildren=1elementname=out,<personatt1="value1"att2="value2">text1</person>,,<person>text2</person>,,<person>text3</person>,value2As we can see, we can explore the XML node structure, attributes, and many other things if you check more on theAPIs.Example #2Let's use the XML path processor from Saxonica.fromsaxonpyimportPySaxonProcessorwithPySaxonProcessor(license=False)asproc:xml="""\<out><person>text1</person><person>text2</person><person>text3</person></out>"""xp=proc.new_xpath_processor()node=proc.parse_xml(xml_text=xml)xp.set_context(xdm_item=node)item=xp.evaluate_single('//person[1]')ifisinstance(item,PyXdmNode):print(item.string_value)# pay attention, Saxon's xdm data typevalue=proc.make_double_value(3.5)print(value.primitive_type_name)The output shows here.text1
Q{http://www.w3.org/2001/XMLSchema}doubleSaxon shows the result given the path.Example #3The XSLT processor, #1fromsaxonpyimportPySaxonProcessorwithPySaxonProcessor(license=False)asproc:xsltproc=proc.new_xslt_processor()document=proc.parse_xml(xml_text="<out><person>text1</person><person>text2</person><person>text3</person></out>")xsltproc.set_source(xdm_node=document)xsltproc.compile_stylesheet(stylesheet_text="<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='2.0'> <xsl:param name='values' select='(2,3,4)' /><xsl:output method='xml' indent='yes' /><xsl:template match='*'><output><xsl:value-of select='//person[1]'/><xsl:for-each select='$values' ><out><xsl:value-of select='. * 3'/></out></xsl:for-each></output></xsl:template></xsl:stylesheet>")output2=xsltproc.transform_to_string()print(output2)Here is the output that shows the result of trasformation.<?xml version="1.0" encoding="UTF-8"?><output>text1<out>6</out><out>9</out><out>12</out></output>Example #4Watch out for the not-pythonic way!fromsaxonpyimportPySaxonProcessorwithPySaxonProcessor(license=False)asproc:xsltproc=proc.new_xslt_processor()xml='<a><b>Text</b></a>'xslt='''\<xsl:stylesheet version="1.0"xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:param name="a" /><xsl:output method='xml' indent='yes' /><xsl:template match="/"><foo><xsl:value-of select="$a" /></foo></xsl:template></xsl:stylesheet>'''document=proc.parse_xml(xml_text=xml)#please note the not Python way in the next two lines.xdm_a=proc.make_string_value('a was given in the parameter')xsltproc.set_parameter('a',xdm_a)xsltproc.set_source(xdm_node=document)xsltproc.compile_stylesheet(stylesheet_text=xslt)output2=xsltproc.transform_to_string()print(output2)Here we use an XSLT/stylesheet parameter. I just want to highlight that Python String (object) is not the same string that Saxon uses, and the same goes for other types. We need to convert to it bymake_string_value. This may be a little exotic and not so pythonic because Saxon is written in Java and cross-compiled for C and then Python. Just be aware of it but you don't need to know anything more about Java or C to use Saxonpy.
Please check out theSaxonica's documentationforxquery, schema validation, and others.Why thewithkeywordwithis good to clear out the underlying processes when the program exits.Source code & DevelopmentWe downloaded the Saxonc HE from theSaxonica's siteWe have the source code on agithub repoto make the wheel packages for Linux and macOS. We havea separate repofor Windows.We use Github actions runners for CI and releases.Our use casesHere at the projects of the University of Virginia, we use Saxon for Tibetan cataloging and SolrDb indexing.