|
21 | 21 |
|
22 | 22 | <!-- Replace heading 1 Markdown with tei:hi h1 Element --> |
23 | 23 | <xsl:template match="text()[matches(., '(^|[^#])#\s+.+')]" mode="markdown-to-tei"> |
24 | | - <xsl:apply-templates select="m2t:h1(.)" mode="#current"/> |
| 24 | + <xsl:sequence select="m2t:h1(.)"/> |
25 | 25 | </xsl:template> |
26 | 26 |
|
27 | 27 | <!-- Replace heading 2 Markdown with tei:hi h2 Element --> |
28 | 28 | <xsl:template match="text()[matches(., '(^|[^#])##\s+.+')]" mode="markdown-to-tei"> |
29 | | - <xsl:apply-templates select="m2t:h2(.)" mode="#current"/> |
| 29 | + <xsl:sequence select="m2t:h2(.)"/> |
30 | 30 | </xsl:template> |
31 | 31 |
|
32 | 32 | <!-- Replace heading 3 Markdown with tei:hi h3 Element --> |
33 | 33 | <xsl:template match="text()[matches(., '(^|[^#])###\s+.+')]" mode="markdown-to-tei"> |
34 | | - <xsl:apply-templates select="m2t:h3(.)" mode="#current"/> |
| 34 | + <xsl:sequence select="m2t:h3(.)"/> |
35 | 35 | </xsl:template> |
36 | 36 |
|
37 | 37 | <!-- Replace bold Markdown with tei:emph bold Element --> |
38 | 38 | <xsl:template match="text()[matches(., '\*\*([^*]+)\*\*')]" mode="markdown-to-tei"> |
39 | | - <xsl:apply-templates select="m2t:bold(.)" mode="#current"/> |
| 39 | + <xsl:sequence select="m2t:bold(.)"/> |
40 | 40 | </xsl:template> |
41 | 41 |
|
42 | 42 | <!-- Replace italic Markdown with tei:emph italic Element --> |
43 | 43 | <xsl:template match="text()[matches(., '(^|[^*\\])\*[^*]*[^*\\]\*([^*]|$)')]" mode="markdown-to-tei"> |
44 | | - <xsl:apply-templates select="m2t:italic(.)" mode="#current"/> |
| 44 | + <xsl:sequence select="m2t:italic(.)"/> |
45 | 45 | </xsl:template> |
46 | | - |
47 | | - <!-- TODO(AR) the rule below adds a <tei:p> wrapper, the tei:p should only be applied when the parent of the text node is an appropriate container e.g. <tei:note> |
48 | | - Ideally we want to keep tei:note and those kind of elements out of this XSLT - they should go in manuforma-form-to-tei.xspec |
49 | | - 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 |
50 | | - --> |
51 | 46 |
|
| 47 | + <!-- Process Markdown paragraphs and convert them into tei:hi and tei:p Elements --> |
52 | 48 | <xsl:template match="text()" mode="markdown-to-tei-container"> |
53 | 49 | <!-- 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]"/> |
| 50 | + <xsl:variable name="paragraphs" as="xs:string*" select="tokenize(., '\n[ \t\r]*\n+')[not(matches(., '^[ \t\r]+$'))][string-length(.) gt 0]"/> |
55 | 51 | <xsl:for-each select="$paragraphs"> |
56 | | - <xsl:variable name="paragraph" select="."/> |
| 52 | + <xsl:variable name="paragraph" as="xs:string" select="."/> |
| 53 | + |
| 54 | + <!-- We now split on /n whilst ignoring misc whitespace to create lines from the paragraph --> |
| 55 | + <xsl:variable name="lines" as="xs:string*" select="tokenize($paragraph, '\n')[not(matches(., '^[ \t\r]+$'))][string-length(.) gt 0]"/> |
| 56 | + <xsl:variable name="first-line" as="xs:string?" select="head($lines)"/> |
| 57 | + <xsl:variable name="remaining-lines" as="xs:string*" select="tail($lines)"/> |
| 58 | + |
57 | 59 | <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"/> |
| 60 | + <xsl:when test="matches($first-line, '^#\s+.+')"> |
| 61 | + <!-- First line is a Markdown heading 1, so process that and then the remaining lines make up the paragraph --> |
| 62 | + <xsl:sequence select="m2t:h1($first-line)"/> |
| 63 | + <xsl:sequence select="m2t:paragraph($remaining-lines)"/> |
61 | 64 | </xsl:when> |
62 | 65 |
|
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 test="matches($first-line, '^##\s+.+')"> |
| 67 | + <!-- First line is a Markdown heading 2, so process that and then the remaining lines make up the paragraph --> |
| 68 | + <xsl:sequence select="m2t:h2($first-line)"/> |
| 69 | + <xsl:sequence select="m2t:paragraph($remaining-lines)"/> |
66 | 70 | </xsl:when> |
67 | 71 |
|
68 | | - <xsl:when test="matches($paragraph, '^###\s+.+')"> |
69 | | - <!-- This is a Markdown heading 3 --> |
70 | | - <xsl:apply-templates select="m2t:h3($paragraph)" mode="#current"/> |
| 72 | + <xsl:when test="matches($first-line, '^###\s+.+')"> |
| 73 | + <!-- First line is a Markdown heading 3, so process that and then the remaining lines make up the paragraph --> |
| 74 | + <xsl:sequence select="m2t:h3($first-line)"/> |
| 75 | + <xsl:sequence select="m2t:paragraph($remaining-lines)"/> |
71 | 76 | </xsl:when> |
72 | 77 |
|
73 | 78 | <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>
</xsl:text></xsl:if> |
82 | | - <xsl:sequence select="m2t:bold-and-italic($line)"/> |
83 | | - </xsl:for-each> |
84 | | - </tei:p> |
| 79 | + <!-- First line is just text, so all lines make up the paragraph --> |
| 80 | + <xsl:sequence select="m2t:paragraph($lines)"/> |
85 | 81 | </xsl:otherwise> |
86 | 82 | </xsl:choose> |
87 | 83 | </xsl:for-each> |
88 | 84 | </xsl:template> |
89 | 85 |
|
90 | | - <!-- Handle Raw text nodes inside some container Element --> |
91 | | - <!-- xsl:template match="text()" mode="markdown-to-tei" priority="-1"> |
92 | | - <xsl:for-each select="tokenize(., '\n[ \t\r]*\n+')[not(matches(., '^[ \t\r]+$'))][string-length(.) gt 0]"> |
93 | | - <xsl:variable name="lines" select="tokenize(., '\n')[not(matches(., '^[ \t\r]+$'))][string-length(.) gt 0]"/> |
94 | | - <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>
</xsl:text></xsl:if><xsl:value-of select="$lines[$i]"/></xsl:for-each></tei:p> |
| 86 | + <!-- Replace non-TEI elements with tei:p if they don't have an ancestor tei:p --> |
| 87 | + <xsl:template match="element()[namespace-uri(.) ne 'http://www.tei-c.org/ns/1.0'][empty(ancestor::tei:p)]" mode="markdown-to-tei"> |
| 88 | + <tei:p> |
| 89 | + <xsl:for-each select="node()"> |
| 90 | + <xsl:choose> |
| 91 | + <xsl:when test=". instance of element() and namespace-uri(.) ne 'http://www.tei-c.org/ns/1.0'"> |
| 92 | + <xsl:apply-templates select="./node()" mode="non-tei-container"/> |
| 93 | + </xsl:when> |
| 94 | + <xsl:otherwise> |
| 95 | + <xsl:apply-templates select="." mode="non-tei-container"/> |
| 96 | + </xsl:otherwise> |
| 97 | + </xsl:choose> |
| 98 | + </xsl:for-each> |
| 99 | + </tei:p> |
| 100 | + </xsl:template> |
| 101 | + |
| 102 | + <!-- Drop non-TEI elements if they have an ancestor tei:p --> |
| 103 | + <xsl:template match="element()[namespace-uri(.) ne 'http://www.tei-c.org/ns/1.0'][ancestor::tei:p]" mode="markdown-to-tei"> |
| 104 | + <xsl:for-each select="node()"> |
| 105 | + <xsl:choose> |
| 106 | + <xsl:when test=". instance of element() and namespace-uri(.) ne 'http://www.tei-c.org/ns/1.0'"> |
| 107 | + <xsl:apply-templates select="./node()" mode="non-tei-container"/> |
| 108 | + </xsl:when> |
| 109 | + <xsl:otherwise> |
| 110 | + <xsl:apply-templates select="." mode="non-tei-container"/> |
| 111 | + </xsl:otherwise> |
| 112 | + </xsl:choose> |
95 | 113 | </xsl:for-each> |
96 | | - </xsl:template --> |
| 114 | + </xsl:template> |
| 115 | + |
| 116 | + <!-- Used above to replace non-TEI elements with tei:p --> |
| 117 | + <xsl:template match="node()|@*" mode="non-tei-container"> |
| 118 | + <xsl:copy> |
| 119 | + <xsl:for-each select="node()|@*"> |
| 120 | + <xsl:choose> |
| 121 | + <xsl:when test=". instance of element() and namespace-uri(.) ne 'http://www.tei-c.org/ns/1.0'"> |
| 122 | + <xsl:apply-templates select="./node()" mode="#current"/> |
| 123 | + </xsl:when> |
| 124 | + <xsl:otherwise> |
| 125 | + <xsl:apply-templates select="." mode="#current"/> |
| 126 | + </xsl:otherwise> |
| 127 | + </xsl:choose> |
| 128 | + </xsl:for-each> |
| 129 | + </xsl:copy> |
| 130 | + </xsl:template> |
97 | 131 |
|
98 | 132 | <!-- Default: Identity trasform everything --> |
99 | 133 | <xsl:template match="node()|@*" mode="markdown-to-tei" priority="-3"> |
100 | 134 | <xsl:copy> |
101 | 135 | <xsl:apply-templates select="node()|@*" mode="#current"/> |
102 | 136 | </xsl:copy> |
103 | 137 | </xsl:template> |
| 138 | + |
| 139 | + <xsl:function name="m2t:paragraph" as="node()*"> |
| 140 | + <xsl:param name="lines" as="item()*" required="yes"/> |
| 141 | + <xsl:if test="exists($lines)"> |
| 142 | + <tei:p> |
| 143 | + <xsl:for-each select="(1 to count($lines))"> |
| 144 | + <xsl:variable name="i" select="." as="xs:integer"/> |
| 145 | + <xsl:variable name="line" select="$lines[$i]"/> |
| 146 | + <xsl:if test="$i gt 1"><tei:lb/><xsl:text>
</xsl:text></xsl:if> |
| 147 | + <xsl:sequence select="m2t:bold-and-italic($line)"/> |
| 148 | + </xsl:for-each> |
| 149 | + </tei:p> |
| 150 | + </xsl:if> |
| 151 | + </xsl:function> |
104 | 152 |
|
105 | 153 | <xsl:function name="m2t:h1" as="node()+"> |
106 | | - <xsl:param name="markdown" required="true"/> |
| 154 | + <xsl:param name="markdown" required="yes"/> |
107 | 155 | <xsl:analyze-string select="$markdown" regex="(^|[^#])#\s+(.+)"> |
108 | 156 | <xsl:matching-substring> |
109 | 157 | <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> |
|
115 | 163 | </xsl:function> |
116 | 164 |
|
117 | 165 | <xsl:function name="m2t:h2" as="node()+"> |
118 | | - <xsl:param name="markdown" required="true"/> |
| 166 | + <xsl:param name="markdown" required="yes"/> |
119 | 167 | <xsl:analyze-string select="$markdown" regex="(^|[^#])##\s+(.+)"> |
120 | 168 | <xsl:matching-substring> |
121 | 169 | <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> |
|
127 | 175 | </xsl:function> |
128 | 176 |
|
129 | 177 | <xsl:function name="m2t:h3" as="node()+"> |
130 | | - <xsl:param name="markdown" required="true"/> |
| 178 | + <xsl:param name="markdown" required="yes"/> |
131 | 179 | <xsl:analyze-string select="$markdown" regex="(^|[^#])###\s+(.+)"> |
132 | 180 | <xsl:matching-substring> |
133 | 181 | <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> |
|
139 | 187 | </xsl:function> |
140 | 188 |
|
141 | 189 | <xsl:function name="m2t:bold" as="node()+"> |
142 | | - <xsl:param name="markdown" required="true"/> |
| 190 | + <xsl:param name="markdown" required="yes"/> |
143 | 191 | <xsl:analyze-string select="$markdown" regex="(^|[^\\])\*\*([^*]*[^*\\])\*\*"> |
144 | 192 | <xsl:matching-substring> |
145 | 193 | <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> |
|
151 | 199 | </xsl:function> |
152 | 200 |
|
153 | 201 | <xsl:function name="m2t:italic" as="node()+"> |
154 | | - <xsl:param name="markdown" required="true"/> |
| 202 | + <xsl:param name="markdown" required="yes"/> |
155 | 203 | <xsl:analyze-string select="$markdown" regex="(^|[^*\\])\*([^*]*[^*\\])\*([^*]|$)"> |
156 | 204 | <xsl:matching-substring> |
157 | 205 | <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> |
|
163 | 211 | </xsl:function> |
164 | 212 |
|
165 | 213 | <xsl:function name="m2t:bold-and-italic" as="node()+"> |
166 | | - <xsl:param name="markdown" required="true"/> |
| 214 | + <xsl:param name="markdown" required="yes"/> |
167 | 215 | <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 | 216 | <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 | 217 | <xsl:sequence select="$after-italic"/> |
170 | 218 | </xsl:function> |
171 | 219 |
|
172 | 220 | <xsl:function name="m2t:non-empty" as="xs:string*"> |
173 | | - <xsl:param name="inputs" as="xs:string*" required="true"/> |
| 221 | + <xsl:param name="inputs" as="xs:string*" required="yes"/> |
174 | 222 | <xsl:sequence select="$inputs[string-length(.) gt 0]"/> |
175 | 223 | </xsl:function> |
176 | 224 |
|
|
0 commit comments