mkogg.py: Fix 'self.get_mp4_metadata(self, source)'
[blog.git] / posts / XSLT.mdwn
1 [[!meta  title="eXtensible Style Language Transforms"]]
2
3 Often data is stored in
4 <abbr title="eXtensible Markup Language">XML</abbr> files must be
5 massaged into other formats (e.g. [[DocBook to roff|DocBook 5]]).
6 There are well developed procedures for defining such transformations
7 ([XSLT][]) and a number of tools to apply them (e.g. [xsltproc][]).
8
9 Besides the [W3 tutorial][w3], there is also a nice
10 [introduction][intro] by Paul Grosso and Norman Walsh.  I've copied a
11 simple [[example|chapter]] from this intro and also included a
12 [[slightly more complicated setup|code]] for generating online help
13 for a list of macros.
14
15 XSLT is also useful for standardizing XML content.  For example, I was
16 recently trying to compare to [[Gramps]] XML files, to see what had
17 changed between two database backups.  Unfortunately, the backup XML
18 was not sorted by `id`, so there were many diff chunks due to node
19 shuffling that didn't represent any useful information.  With the
20 following XSLT:
21
22     <?xml version="1.0"?>
23     <xsl:stylesheet version="1.0"
24                     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
25         <xsl:output method="xml" indent="yes"/>
26         <xsl:strip-space elements="*"/>
27         <!-- identity transform -->
28         <xsl:template match="@*|node()">
29                 <xsl:copy>
30                         <xsl:apply-templates select="@*|node()"/>
31                 </xsl:copy>
32         </xsl:template>
33         <!-- sort node children by their `id` attributes -->
34         <xsl:template match="node()">
35                 <xsl:copy>
36                         <xsl:apply-templates select="@*"/>
37                         <xsl:for-each select="node()">
38                                 <xsl:sort select="@id" order="ascending"/>
39                                 <xsl:apply-templates select="."/>
40                         </xsl:for-each>
41                 </xsl:copy>
42         </xsl:template>
43     </xsl:stylesheet>
44
45 With the above saved as `sort-by-id.xsl`, you can sort `some.xml` using
46
47     $ xsltproc --nonet --novalid sort-by-id.xsl some.xml
48
49 You can compare two [[Gramps]] XML files with
50
51     $ diff -u <(zcat a.gramps | xsltproc --nonet --novalid sort-by-id.xsl -)
52               <(zcat b.gramps | xsltproc --nonet --novalid sort-by-id.xsl -) | less
53
54 Jesper Tverskov has a nice page about [the identity template and
55 related tricks][identity] if you want more examples of quasi-copy
56 transforms.
57
58 [XSLT]: http://www.w3.org/TR/xslt
59 [w3]: http://www.w3schools.com/xsl/
60 [intro]: http://nwalsh.com/docs/tutorials/xsl/xsl/slides.html
61 [xsltproc]: http://www.xmlsoft.org/XSLT/
62 [identity]: http://www.xmlplease.com/xsltidentity
63
64 [[!tag tags/tools]]
65 [[!tag tags/web]]