6.6. XSLT

  • Using lxml module

6.6.1. Use Case - 0x01

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>

6.6.2. Use Case - 0x02

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>

6.6.3. Use Case - 0x03

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>

6.7. Assignments

Code 6.63. Solution
"""
* Assignment: Serialization XML Parsing
* Complexity: easy
* Lines of code: 20 lines
* Time: 13 min

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ść
"""

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>"""


Code 6.64. Solution
"""
* Assignment: Serialization XSLT Transformation
* Complexity: medium
* Lines of code: 5 lines
* Time: 13 min

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ść
"""

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>
"""