Hi Stefan,

Many thanks for your thoughts.  I hadn't considered just executing an XPath query directly against the XSL as simple XML – but that works!  I combined this idea with your xpath expression and now have a function that will return the correct value:

def get_variable_from_xsl(variable_name, xsl):
    xpath_results = xsl.xpath("//xsl:variable[@name=$name]", name=variable_name,
    for xpath_result in xpath_results:
        if xpath_result.get('name') == variable_name:
            for xpath_child in xpath_result.getchildren():
                if 'select' in xpath_child.keys():
                    return xpath_child.get('select')
    return None        

destination_url = get_variable_from_xsl('destination_url', xsl)
print(f"destination_url = {destination_url}")

Which returns:

destination_url = 'https://my.domain.example.com/'

Thanks again!


On Wed, 10 Apr 2019 at 18:25, Stefan Behnel <stefan_ml@behnel.de> wrote:
Adrian Bool schrieb am 10.04.19 um 10:49:
> I'm trying to extract from data from XSL files on an IBM DataPower system.
> I can't change the XSLT files - and therefore need to work around their
> current structure to get the info I need.

Well, XSL is XML, so you can always post-process the XSL document after
parsing it as XML, before you pass it into the XSLT() constructor.

> I'm doing this from within Python 3.7 using etree.__version__ 4.3.3.
> Here are my imports, a dummy XML object and a cutdown version of the XSL
> file from the IBM system:
>     from lxml import etree
>     from textwrap import dedent
>     xml = etree.XML("""<root></root>""")
>     xsl = etree.XML(dedent(
>         """<?xml version="1.0"?>
>         <xsl:stylesheet version="1.0"
>         xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>         xmlns:dp="http://www.datapower.com/extensions"
>         extension-element-prefixes="dp">
>         <xsl:template match="node()|@*">
>     <xsl:copy>
>     <xsl:apply-templates select="node()|@*"/>
>     </xsl:copy>
>             <xsl:variable name="destination_url">
>                 <xsl:value-of select="'https://my.domain.example.com/'" />
>             </xsl:variable>
>             <!--Set the destination URL in the context variable-->
>             <dp:set-variable name="'var://context/mpgw/Destination'"
> value="$destination_url" />

I don't think I've ever tried this myself in lxml. I guess I would have
expected value="{$destination_url}" rather than the plain variable
reference here. Can't say how XSLT is meant to deal with this.

>         </xsl:template>
>         </xsl:stylesheet>
>         """))
> My goal is to use lxml to process this file and extract the contents of the
> DataPower variable 'var://context/mpgw/Destination' - i.e. the contents of
> the xsl:variable $destination_url - in the above case '
> https://my.domain.example.com/'.
> I've created an XSLT extension for the "dp:set-variable" element to try to
> capture this information:
>     class MyExtElement(etree.XSLTExtension):
>         def execute(self, context, self_node, input_node, output_parent):
>             if self_node.tag == '{
> http://www.datapower.com/extensions}set-variable':
>                 print(f"Setting variable of name {self_node.get('name')} to
> value {self_node.get('value')}")
>     extensions = { ('http://www.datapower.com/extensions', 'set-variable')
> : MyExtElement() }
>     result = etree.XSLT(xsl, extensions=extensions)(xml)
>     print(f"Result: {result}")
> When this is being called; instead of the value of destination_url I'm
> getting the static "$destination_url" string instead - with the output of
> the above script being:
>     Setting variable of name 'var://context/mpgw/Destination' to value
> $destination_url
>     Result: <?xml version="1.0"?>
>     <root/>
> I am rather suprised that the $destination_url xsl:variable was not being
> evaluated - does anyone know why this is the case?
> Given the above, I've been trying to find a way to access the
> $destination_url xsl:variable from within my XSLTExtension - but
> unfortunately with no luck.

Did you try looking it up in the XSL document via XPath? Something like

  .xpath("//xsl:variable[@name=$name]", name="destination_url")

(plus namespaces)

Mailing list for the lxml Python XML toolkit - http://lxml.de/