bhylu.com

Advertisements

XML XSLT Basics

XSLT creates a result tree or text output from an input tree. Start with a template matching the document and an explicit output method.

How it works

XSLT is a language for transformations, XPath supplies its selections and expressions, and XSL-FO is a separate formatting vocabulary. A stylesheet is an XML document in the XSLT namespace, not ordinary HTML with a few magic tags. The local Python lab runs XSLT 1.0 through libxslt with file and network access denied. Later Saxon examples deliberately identify XSLT 3.0 features rather than silently mixing processor versions.

Run the code

Use Python 3 with lxml 6.1.1 in a separate virtual environment. The complete listing embeds its own XML and any schema or stylesheet; run python xslt-first.py. It does not need Apache or MySQL. The shared restrictive parse function rejects declarations for untrusted input. The trusted DTD/entity and streaming lessons explicitly explain their separate fixed-input boundaries.

Download the complete xslt-first.py source. Keep each lab in its own folder. Sources are served as text, not as public executable server scripts. Review the starting setup.

Example

xslt-first.py

from lxml import etree as E

class DenyExternal(E.Resolver):
    def resolve(self, url, public_id, context):
        raise ValueError("External resources are disabled")

def parse(text):
    if "<!DOCTYPE" in text.upper() or "<!ENTITY" in text.upper():
        raise ValueError("Declarations are disabled for untrusted XML")
    parser = E.XMLParser(resolve_entities=False, load_dtd=False,
                         no_network=True, huge_tree=False)
    parser.resolvers.add(DenyExternal())
    return E.fromstring(text.encode("utf-8"), parser)

source = "<exchange region=\"west\">\n  <packet id=\"p1\" available=\"true\"><name>Marigold</name><quantity>12</quantity><category>flower</category></packet>\n  <packet id=\"p2\" available=\"false\"><name>Fenugreek</name><quantity>0</quantity><category>herb</category></packet>\n  <packet id=\"p3\" available=\"true\"><name>Basil</name><quantity>7</quantity><category>herb</category></packet>\n</exchange>"
root = parse(source)
style_source = "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n  <xsl:output method=\"text\" omit-xml-declaration=\"yes\"/>\n  <xsl:template match=\"/\"><xsl:text>Packets: </xsl:text><xsl:value-of select=\"count(exchange/packet)\"/></xsl:template>\n</xsl:stylesheet>"
transform = E.XSLT(parse(style_source), access_control=E.XSLTAccessControl.DENY_ALL)
print(str(transform(root)), end="")

Expected result

Packets: 3

The template matches the document node and counts packet elements under exchange. The output is plain text because xsl:output says so. There is no browser stylesheet dependency or hidden input file.

Check the exact contract in the XML specification, XPath 1.0, the XSD 1.0 primer, lxml validation documentation and Saxon’s processor documentation.