5.6. XML XSLT
Using
lxml
module
5.6.1. Use Case - 1
from io import StringIO
from lxml.etree import XML, XSLT, parse
TEMPLATE = """
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<my_tag>
<xsl:value-of select="/outer/inner/text()" />
</my_tag>
</xsl:template>
</xsl:stylesheet>
"""
DATA = """
<outer>
<inner>Hello World</inner>
</outer>
"""
transform = XSLT(XML(TEMPLATE))
data = parse(StringIO(DATA))
result = transform(data)
print(result)
# <?xml version="1.0"?>
# <my_tag>Hello World</my_tag>
5.6.2. Use Case - 2
from io import StringIO
from lxml.etree import XML, XSLT, parse
DATA = """
<users>
<user>
<firstname>Mark</firstname>
<lastname>Watney</lastname>
</user>
<user>
<firstname>Melissa</firstname>
<lastname>Lewis</lastname>
</user>
</users>
"""
TEMPLATE = """
<html xsl:version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<table>
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
</tr>
</thead>
<tbody>
<xsl:for-each select="users/user">
<tr>
<td><xsl:value-of select="firstname"/></td>
<td><xsl:value-of select="lastname"/></td>
</tr>
</xsl:for-each>
</tbody>
</table>
</html>
"""
transform = XSLT(XML(TEMPLATE))
data = parse(StringIO(DATA))
result = transform(data)
print(result)
# <html><table>
# <thead><tr>
# <th>First Name</th>
# <th>Last Name</th>
# </tr></thead>
# <tbody>
# <tr>
# <td>Mark</td>
# <td>Watney</td>
# </tr>
# <tr>
# <td>Melissa</td>
# <td>Lewis</td>
# </tr>
# </tbody>
# </table></html>
5.6.3. Use Case - 3
from io import StringIO
from lxml.etree import XML, XSLT, parse
DATA = """
<CATALOG>
<PLANT>
<COMMON>Bloodroot</COMMON>
<BOTANICAL>Sanguinaria canadensis</BOTANICAL>
<ZONE>4</ZONE>
<LIGHT>Mostly Shady</LIGHT>
<PRICE>$2.44</PRICE>
<AVAILABILITY>031599</AVAILABILITY>
</PLANT>
<PLANT>
<COMMON>Columbine</COMMON>
<BOTANICAL>Aquilegia canadensis</BOTANICAL>
<ZONE>3</ZONE>
<LIGHT>Mostly Shady</LIGHT>
<PRICE>$9.37</PRICE>
<AVAILABILITY>030699</AVAILABILITY>
</PLANT>
</CATALOG>
"""
TEMPLATE = """
<html xsl:version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<style>
body {font-family: Arial; font-size: 1em; background-color: #EEEEEE}
div.title {background-color: teal; color: white; padding: 4px}
div.description {margin-left:20px;margin-bottom:1em;font-size:10pt}
span {font-weight: bold}
</style>
<body>
<xsl:for-each select="CATALOG/PLANT">
<div class="title">
<span><xsl:value-of select="BOTANICAL"/></span>
<xsl:value-of select="PRICE"/>
</div>
<div class="description">
<xsl:value-of select="description"/>
<span> (<xsl:value-of select="AVAILABILITY"/> will be available)</span>
</div>
</xsl:for-each>
</body>
</html>
"""
transform = XSLT(XML(TEMPLATE))
data = parse(StringIO(DATA))
result = transform(data)
print(result)
# <html>
# <style>
# body {font-family: Arial; font-size: 1em; background-color: #EEEEEE}
# div.title {background-color: teal; color: white; padding: 4px}
# div.description {margin-left:20px;margin-bottom:1em;font-size:10pt}
# span {font-weight: bold}
# </style>
# <body>
# <div class="title">
# <span>Sanguinaria canadensis</span>$2.44</div>
# <div class="description"><span> (031599 will be available)</span></div>
# <div class="title">
# <span>Aquilegia canadensis</span>$9.37</div>
# <div class="description"><span> (030699 will be available)</span></div>
# </body>
# </html>
5.6.4. Assignments
# FIXME: Write automated tests
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: Serialization XML Parsing
# - Difficulty: easy
# - Lines: 20
# - Minutes: 13
# %% English
# 1. Convert input data to `list[dict]`
# 2. Run doctests - all must succeed
# %% Polish
# 1. Przekonwertuj dane wejściowe do `list[dict]`
# 2. Uruchom doctesty - wszystkie muszą się powieść
# %% Tests
"""
"""
# %% Setup
DATA = """<?xml version="1.0" encoding="UTF-8"?>
<CATALOG>
<PLANT>
<COMMON>Bloodroot</COMMON>
<BOTANICAL>Sanguinaria canadensis</BOTANICAL>
<ZONE>4</ZONE>
<LIGHT>Mostly Shady</LIGHT>
<PRICE>$2.44</PRICE>
<AVAILABILITY>031599</AVAILABILITY>
</PLANT>
<PLANT>
<COMMON>Columbine</COMMON>
<BOTANICAL>Aquilegia canadensis</BOTANICAL>
<ZONE>3</ZONE>
<LIGHT>Mostly Shady</LIGHT>
<PRICE>$9.37</PRICE>
<AVAILABILITY>030699</AVAILABILITY>
</PLANT>
<PLANT>
<COMMON>Marsh Marigold</COMMON>
<BOTANICAL>Caltha palustris</BOTANICAL>
<ZONE>4</ZONE>
<LIGHT>Mostly Sunny</LIGHT>
<PRICE>$6.81</PRICE>
<AVAILABILITY>051799</AVAILABILITY>
</PLANT>
<PLANT>
<COMMON>Cowslip</COMMON>
<BOTANICAL>Caltha palustris</BOTANICAL>
<ZONE>4</ZONE>
<LIGHT>Mostly Shady</LIGHT>
<PRICE>$9.90</PRICE>
<AVAILABILITY>030699</AVAILABILITY>
</PLANT>
<CATALOG>"""
# FIXME: Write tests
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: Serialization XSLT Transformation
# - Difficulty: medium
# - Lines: 5
# - Minutes: 13
# %% English
# 1. Convert input data to `list[dict]`
# 2. Run doctests - all must succeed
# %% Polish
# 1. Przekonwertuj dane wejściowe do `list[dict]`
# 2. Uruchom doctesty - wszystkie muszą się powieść
# %% Tests
"""
"""
# %% Setup
DATA = """<?xml version="1.0" encoding="UTF-8"?>
<breakfast_menu>
<food>
<name>Belgian Waffles</name>
<price>$5.95</price>
<description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>
<calories>650</calories>
</food>
<food>
<name>Strawberry Belgian Waffles</name>
<price>$7.95</price>
<description>Light Belgian waffles covered with strawberries and whipped cream</description>
<calories>900</calories>
</food>
<food>
<name>Berry-Berry Belgian Waffles</name>
<price>$8.95</price>
<description>Light Belgian waffles covered with an assortment of fresh berries and whipped cream</description>
<calories>900</calories>
</food>
<food>
<name>French Toast</name>
<price>$4.50</price>
<description>Thick slices made from our homemade sourdough bread</description>
<calories>600</calories>
</food>
<food>
<name>Homestyle Breakfast</name>
<price>$6.95</price>
<description>Two eggs, bacon or sausage, toast, and our ever-popular hash browns</description>
<calories>950</calories>
</food>
</breakfast_menu>
"""