Skip to content

Commit 6347f31

Browse files
committed
fixup! fixup! New implementation of TEI to Markdown, and Markdown to TEI conversions using XSLT
1 parent ea86943 commit 6347f31

3 files changed

Lines changed: 82 additions & 23 deletions

File tree

src/main/xar-resources/services/manuforma-form-to-tei.xslt

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,23 @@
3030
</xsl:copy>
3131
</xsl:template>
3232

33-
<xsl:template match="tei:note|tei:summary[not(parent::tei:layoutDesc)]|tei:quote">
33+
<!-- Elements that match this template are Markdown containers -->
34+
<xsl:template match="tei:note|tei:summary[not(parent::tei:layoutDesc)]|tei:quote|tei:ab">
3435
<xsl:copy>
3536
<xsl:apply-templates select="@*"/>
36-
<xsl:apply-templates select="node()" mode="markdown-to-tei"/>
37+
<xsl:for-each select="node()">
38+
<xsl:choose>
39+
<xsl:when test=". instance of text()">
40+
<xsl:apply-templates select="." mode="markdown-to-tei-container"/>
41+
</xsl:when>
42+
<xsl:otherwise>
43+
<xsl:apply-templates select="." mode="markdown-to-tei"/>
44+
</xsl:otherwise>
45+
</xsl:choose>
46+
</xsl:for-each>
47+
48+
<!-- xsl:apply-templates select="node()" mode="markdown-to-tei"/ -->
49+
3750
</xsl:copy>
3851
</xsl:template>
3952

@@ -44,12 +57,14 @@
4457
</xsl:call-template>
4558
</xsl:template>
4659

60+
<!--
4761
<xsl:template match="tei:ab">
4862
<xsl:copy>
4963
<xsl:apply-templates select="@*"/>
5064
<xsl:apply-templates select="node()" mode="markdown-to-tei"/>
5165
</xsl:copy>
5266
</xsl:template>
67+
-->
5368

5469
<!-- Add a Contributor into the titleStmt Element -->
5570
<xsl:template match="tei:titleStmt">

src/main/xar-resources/services/markdown-to-tei.xslt

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,51 @@
4949
Figure out whether it's best to move the tei:p creation to the manuforma-form-to-tei.xspec or to send some sort of mode/flag through to here and use different templates
5050
-->
5151

52+
<xsl:template match="text()" mode="markdown-to-tei-container">
53+
<!-- First we split on /n/n+ whilst ignoring misc whitespace to create headings or paragraphs -->
54+
<xsl:variable name="paragraphs" select="tokenize(., '\n[ \t\r]*\n+')[not(matches(., '^[ \t\r]+$'))][string-length(.) gt 0]"/>
55+
<xsl:for-each select="$paragraphs">
56+
<xsl:variable name="paragraph" select="."/>
57+
<xsl:choose>
58+
<xsl:when test="matches($paragraph, '^#\s+.+')">
59+
<!-- This is a Markdown heading 1 -->
60+
<xsl:apply-templates select="m2t:h1($paragraph)" mode="#current"/>
61+
</xsl:when>
62+
63+
<xsl:when test="matches($paragraph, '^##\s+.+')">
64+
<!-- This is a Markdown heading 2 -->
65+
<xsl:apply-templates select="m2t:h2($paragraph)" mode="#current"/>
66+
</xsl:when>
67+
68+
<xsl:when test="matches($paragraph, '^###\s+.+')">
69+
<!-- This is a Markdown heading 3 -->
70+
<xsl:apply-templates select="m2t:h3($paragraph)" mode="#current"/>
71+
</xsl:when>
72+
73+
<xsl:otherwise>
74+
<!-- This is a Markdown paragraph -->
75+
<tei:p>
76+
<!-- We now split on /n whilst ignoring misc whitespace to create lines within a paragraph -->
77+
<xsl:variable name="lines" select="tokenize($paragraph, '\n')[not(matches(., '^[ \t\r]+$'))][string-length(.) gt 0]"/>
78+
<xsl:for-each select="(1 to count($lines))">
79+
<xsl:variable name="i" select="." as="xs:integer"/>
80+
<xsl:variable name="line" select="$lines[$i]"/>
81+
<xsl:if test="$i gt 1"><tei:lb/><xsl:text>&#xA;</xsl:text></xsl:if>
82+
<xsl:sequence select="m2t:bold-and-italic($line)"/>
83+
</xsl:for-each>
84+
</tei:p>
85+
</xsl:otherwise>
86+
</xsl:choose>
87+
</xsl:for-each>
88+
</xsl:template>
5289

5390
<!-- Handle Raw text nodes inside some container Element -->
54-
<xsl:template match="text()" mode="markdown-to-tei" priority="-1">
91+
<!-- xsl:template match="text()" mode="markdown-to-tei" priority="-1">
5592
<xsl:for-each select="tokenize(., '\n[ \t\r]*\n+')[not(matches(., '^[ \t\r]+$'))][string-length(.) gt 0]">
5693
<xsl:variable name="lines" select="tokenize(., '\n')[not(matches(., '^[ \t\r]+$'))][string-length(.) gt 0]"/>
5794
<tei:p><xsl:for-each select="(1 to count($lines))"><xsl:variable name="i" select="." as="xs:integer"/><xsl:if test="$i gt 1"><tei:lb/><xsl:text>&#xA;</xsl:text></xsl:if><xsl:value-of select="$lines[$i]"/></xsl:for-each></tei:p>
5895
</xsl:for-each>
59-
</xsl:template>
96+
</xsl:template -->
6097

6198
<!-- Default: Identity trasform everything -->
6299
<xsl:template match="node()|@*" mode="markdown-to-tei" priority="-3">
@@ -66,10 +103,10 @@
66103
</xsl:template>
67104

68105
<xsl:function name="m2t:h1" as="node()+">
69-
<xsl:param name="markdown" as="text()" required="true"/>
106+
<xsl:param name="markdown" required="true"/>
70107
<xsl:analyze-string select="$markdown" regex="(^|[^#])#\s+(.+)">
71108
<xsl:matching-substring>
72-
<xsl:if test="m2t:non-empty(regex-group(1))"><xsl:value-of select="regex-group(1)"/></xsl:if><tei:hi rend="h1"><xsl:value-of select="normalize-space(regex-group(2))"/></tei:hi>
109+
<xsl:if test="m2t:non-empty(regex-group(1))"><xsl:value-of select="regex-group(1)"/></xsl:if><tei:hi rend="h1"><xsl:sequence select="m2t:bold-and-italic(normalize-space(regex-group(2)))"/></tei:hi>
73110
</xsl:matching-substring>
74111
<xsl:non-matching-substring>
75112
<xsl:value-of select="."/>
@@ -78,10 +115,10 @@
78115
</xsl:function>
79116

80117
<xsl:function name="m2t:h2" as="node()+">
81-
<xsl:param name="markdown" as="text()" required="true"/>
118+
<xsl:param name="markdown" required="true"/>
82119
<xsl:analyze-string select="$markdown" regex="(^|[^#])##\s+(.+)">
83120
<xsl:matching-substring>
84-
<xsl:if test="m2t:non-empty(regex-group(1))"><xsl:value-of select="regex-group(1)"/></xsl:if><tei:hi rend="h2"><xsl:value-of select="normalize-space(regex-group(2))"/></tei:hi>
121+
<xsl:if test="m2t:non-empty(regex-group(1))"><xsl:value-of select="regex-group(1)"/></xsl:if><tei:hi rend="h2"><xsl:sequence select="m2t:bold-and-italic(normalize-space(regex-group(2)))"/></tei:hi>
85122
</xsl:matching-substring>
86123
<xsl:non-matching-substring>
87124
<xsl:value-of select="."/>
@@ -90,10 +127,10 @@
90127
</xsl:function>
91128

92129
<xsl:function name="m2t:h3" as="node()+">
93-
<xsl:param name="markdown" as="text()" required="true"/>
130+
<xsl:param name="markdown" required="true"/>
94131
<xsl:analyze-string select="$markdown" regex="(^|[^#])###\s+(.+)">
95132
<xsl:matching-substring>
96-
<xsl:if test="m2t:non-empty(regex-group(1))"><xsl:value-of select="regex-group(1)"/></xsl:if><tei:hi rend="h3"><xsl:value-of select="normalize-space(regex-group(2))"/></tei:hi>
133+
<xsl:if test="m2t:non-empty(regex-group(1))"><xsl:value-of select="regex-group(1)"/></xsl:if><tei:hi rend="h3"><xsl:sequence select="m2t:bold-and-italic(normalize-space(regex-group(2)))"/></tei:hi>
97134
</xsl:matching-substring>
98135
<xsl:non-matching-substring>
99136
<xsl:value-of select="."/>
@@ -102,7 +139,7 @@
102139
</xsl:function>
103140

104141
<xsl:function name="m2t:bold" as="node()+">
105-
<xsl:param name="markdown" as="text()" required="true"/>
142+
<xsl:param name="markdown" required="true"/>
106143
<xsl:analyze-string select="$markdown" regex="(^|[^\\])\*\*([^*]*[^*\\])\*\*">
107144
<xsl:matching-substring>
108145
<xsl:if test="m2t:non-empty(regex-group(1))"><xsl:value-of select="regex-group(1)"/></xsl:if><tei:emph rend="bold"><xsl:value-of select="regex-group(2)"/></tei:emph>
@@ -114,7 +151,7 @@
114151
</xsl:function>
115152

116153
<xsl:function name="m2t:italic" as="node()+">
117-
<xsl:param name="markdown" as="text()" required="true"/>
154+
<xsl:param name="markdown" required="true"/>
118155
<xsl:analyze-string select="$markdown" regex="(^|[^*\\])\*([^*]*[^*\\])\*([^*]|$)">
119156
<xsl:matching-substring>
120157
<xsl:if test="m2t:non-empty(regex-group(1))"><xsl:value-of select="regex-group(1)"/></xsl:if><tei:emph rend="italic"><xsl:value-of select="regex-group(2)"/></tei:emph><xsl:if test="m2t:non-empty(regex-group(3))"><xsl:value-of select="regex-group(3)"/></xsl:if>
@@ -124,6 +161,13 @@
124161
</xsl:non-matching-substring>
125162
</xsl:analyze-string>
126163
</xsl:function>
164+
165+
<xsl:function name="m2t:bold-and-italic" as="node()+">
166+
<xsl:param name="markdown" required="true"/>
167+
<xsl:variable name="after-bold" select="for $x in $markdown return if ($x instance of text() or $x instance of xs:string) then m2t:bold($x) else $x"/>
168+
<xsl:variable name="after-italic" select="for $x in $after-bold return if ($x instance of text() or $x instance of xs:string) then m2t:italic($x) else $x"/>
169+
<xsl:sequence select="$after-italic"/>
170+
</xsl:function>
127171

128172
<xsl:function name="m2t:non-empty" as="xs:string*">
129173
<xsl:param name="inputs" as="xs:string*" required="true"/>

src/test/xar-resources/services/manuforma-form-to-tei.xspec

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151

5252
</x:scenario>
5353

54-
<x:scenario label="When it contains paragraphs">
54+
<x:scenario label="When it contains paragraph child elements">
5555
<x:context>
5656
<tei:note>
5757
<tei:p><tei:emph rend="bold">Hello</tei:emph> there and welcome</tei:p>
@@ -68,7 +68,7 @@
6868

6969
</x:scenario>
7070

71-
<x:scenario label="When it contains non-paragraphs">
71+
<x:scenario label="When it contains non-paragraph child elements">
7272
<x:context>
7373
<tei:note>
7474
<something><tei:emph rend="bold">Hello</tei:emph> there <unknown>and</unknown> welcome</something>
@@ -77,13 +77,13 @@
7777
</x:context>
7878

7979
<x:expect label="Then copy as is">
80-
<something><tei:emph rend="bold">Hello</tei:emph> there <unknown>and</unknown> welcome</something>
81-
<other>Goodbye, and see you <tei:emph rend="italic">again</tei:emph> soon</other>
80+
<tei:p><tei:emph rend="bold">Hello</tei:emph> there and welcome</tei:p>
81+
<tei:p>Goodbye, and see you <tei:emph rend="italic">again</tei:emph> soon</tei:p>
8282
</x:expect>
8383

8484
</x:scenario>
8585

86-
<x:scenario label="When it contains paragraphs and non-paragraphs">
86+
<x:scenario label="When it contains paragraphs and non-paragraph child elements">
8787
<x:context>
8888
<tei:note>
8989
<tei:p><tei:emph rend="bold">Hello</tei:emph> there <unknown>and</unknown> welcome</tei:p>
@@ -92,8 +92,8 @@
9292
</x:context>
9393

9494
<x:expect label="Then copy as is">
95-
<tei:p><tei:emph rend="bold">Hello</tei:emph> there <unknown>and</unknown> welcome</tei:p>
96-
<other>Goodbye, and see you <tei:emph rend="italic">again</tei:emph> soon</other>
95+
<tei:p><tei:emph rend="bold">Hello</tei:emph> there and welcome</tei:p>
96+
<tei:p>Goodbye, and see you <tei:emph rend="italic">again</tei:emph> soon</tei:p>
9797
</x:expect>
9898

9999
</x:scenario>
@@ -268,7 +268,7 @@ text.</tei:p>
268268
<tei:TEI>
269269
<tei:note># This is a level 1 heading
270270
Some text here.</tei:note>
271-
</tei:TEI>
271+
</tei:TEI>
272272
</x:context>
273273

274274
<x:expect label="Wrap heading in a h1 element and text in a p element">
@@ -286,9 +286,9 @@ Some text here.</tei:note>
286286

287287
<x:context>
288288
<tei:TEI>
289-
<tei:note># This is a level 2 heading
289+
<tei:note>## This is a level 2 heading
290290
Some text here.</tei:note>
291-
</tei:TEI>
291+
</tei:TEI>
292292
</x:context>
293293

294294
<x:expect label="Wrap heading in a h2 element and text in a p element">
@@ -306,7 +306,7 @@ Some text here.</tei:note>
306306

307307
<x:context>
308308
<tei:TEI>
309-
<tei:note># This is a level 3 heading
309+
<tei:note>### This is a level 3 heading
310310
Some text here.</tei:note>
311311
</tei:TEI>
312312
</x:context>

0 commit comments

Comments
 (0)