stylesheet version="1.0" { output text; strip-space *; variable version := "2.0.4"; variable xslt-keywords := concat( ",", "analyze-string,", "apply-imports,", "apply-templates,", "attribute,", "attribute-set,", "call,", "call-template,", "character-map,", "choose,", "comment,", "copy,", "copy-of,", "decimal-format,", "document,", "element,", "else,", "fallback,", "for-each,", "for-each-group,", "function,", "if,", "import,", "import-schema,", "include,", "key,", "match,", "matching-substring,", "message,", "namespace,", "namespace-alias,", "next-match,", "non-matching-substring,", "number,", "otherwise,", "output,", "output-character,", "perform-sort,", "preserve-space,", "processing-instruction,", "result-document,", "sequence,", "sort,", "strip-space,", "stylesheet,", "template,", "text,", "transform,", "value-of,", "variable,", "when,", "xmlns,"); template write-attribute() { variable name:=name(); value-of (' '); if (contains($xslt-keywords, concat(",",$name,","))) { value-of ('@'); } value-of ($name); value-of ('='); call write-quoted(name := .); } template write-attributes(name1 := '', type1 := '', quoted1 := '', quoted2 := '', xpath1 := '', xpath2 := '', text1 := '', text2 := '', except1 := '', except2 := '', except3 := '') { for-each (@*[name()=$name1]) { call write-name(name := .); } for-each (@*[name()=$type1]) { value-of (' :'); call write-name(name := .); } for-each (@*[name()=$quoted1]) { value-of (' '); call write-quoted(name := .); } for-each (@*[name()=$xpath1]) { call write-xpath(name := .); } for-each (@*[name()=$text1]) { value-of (' '); call write-text(name := .); } for-each (@*[name()=$quoted2]) { value-of ('='); call write-quoted(name := .); } for-each (@*[name()=$xpath2]) { value-of (' = '); call write-xpath(name := .); } for-each (@*[name()=$text2]) { value-of (' = '); call write-text(name := .); } for-each (@*[name()!=$name1 and name()!=$type1 and name()!=$quoted1 and name()!=$quoted2 and name()!=$xpath1 and name()!=$xpath2 and name()!=$text1 and name()!=$text2 and name()!=$except1 and name()!=$except2 and name()!=$except3]) { sort(.); call write-attribute(); } } template write-indentation() { value-of (' '); for-each (ancestor::*) { if (self::xsl:choose and count(node())=2 and xsl:otherwise); else if (self::xsl:otherwise/xsl:choose and count(../node())=2); else { value-of (' '); } } } template write-keyword(name := local-name()) { call write-indentation(); value-of ($name); } template write-name(name, prefix := ' ') { value-of ($prefix); if (contains($name,'{')) { value-of ('"'); call write-text(name := $name, quote:='"'); value-of ('"'); } else { value-of ($name); } } template write-namespace() { call write-indentation(); value-of ('xmlns'); if (name()) { value-of (':'); value-of (name()); } value-of ('='); call write-quoted(name := .); } template write-nodes(except := '', no-punct := false()) { if (node()[name()!=$except]) { if (not($no-punct)) { value-of (' {'); } apply-templates (text()|node()[name()!=$except]); if (not($no-punct)) { call write-keyword(name := '}'); } } else { apply-templates (text()|node()[name()!=$except]); if (not($no-punct)) { value-of (';'); } } } template write-parameters(parameters) { value-of ('('); for-each ($parameters) { call write-name(name := @name, prefix := ''); if (@as) { value-of(' :'); call write-name(name := @as); } if (@select or node()) { value-of(' := '); } if (@select) { call write-xpath(name := @select, no-punct := true()); } if (node() or @*[name()!='name' and name()!='as' and name()!='select']) { value-of(' {'); call write-attributes(except1 := 'name', except2 := 'as', except3:='select'); if (node()) { call write-nodes(no-punct:=true()); } value-of('}'); } if (position() != last()) { value-of (', '); } } value-of (')'); } template write-quoted(name) { value-of ('"'); call write-text(name := $name, quote:='"'); value-of ('"'); } template write-text(name, normalize-space := true(), quote:='') { choose { when (not($name)); when (contains($name,'&')) { call write-text(name := substring-before($name,'&'), normalize-space := $normalize-space, quote:=$quote); value-of ('&amp;'); call write-text(name := substring-after($name,'&'), normalize-space := $normalize-space, quote:=$quote); } when (($quote != '') and contains($name,$quote)) { call write-text(name := substring-before($name,$quote), normalize-space := $normalize-space, quote:=$quote); if ($quote='"') { value-of ('&quot;'); } else { value-of ('&apos;'); } variable suffix := substring-after($name,$quote); if (contains($suffix,$quote)) { call write-text(name := substring-before($suffix,$quote), normalize-space := false(), quote:=$quote); if ($quote='"') { value-of ('&quot;'); } else { value-of ('&apos;'); } call write-text(name := substring-after($suffix,$quote), normalize-space := $normalize-space, quote:=$quote); } else { call write-text(name := $suffix, normalize-space := $normalize-space, quote:=$quote); } } when (($quote = '') and contains($name,'"') and not(contains(substring-before($name,'"'), "'"))) { call write-text(name := substring-before($name,'"'), normalize-space := $normalize-space, quote:=$quote); value-of ('"'); variable suffix := substring-after($name,'"'); if (contains($suffix,'"')) { call write-text(name := substring-before($suffix,'"'), normalize-space := false(), quote:='"'); value-of ('"'); call write-text(name := substring-after($suffix,'"'), normalize-space := $normalize-space, quote:=$quote); } else { call write-text(name := $suffix, normalize-space := $normalize-space, quote:=$quote); } } when (($quote = '') and contains($name, "'")) { call write-text(name := substring-before($name, "'"), normalize-space := $normalize-space, quote:=$quote); value-of ("'"); variable suffix := substring-after($name, "'"); if (contains($suffix, "'")) { call write-text(name := substring-before($suffix, "'"), normalize-space := false(), quote:="'"); value-of ("'"); call write-text(name := substring-after($suffix, "'"), normalize-space := $normalize-space, quote:=$quote); } else { call write-text(name := $suffix, normalize-space := $normalize-space, quote:=$quote); } } when (contains($name,'"')) { call write-text(name := substring-before($name,'"'), normalize-space := $normalize-space, quote:=$quote); value-of ('"'); call write-text(name := substring-after($name,'"'), normalize-space := $normalize-space, quote:=$quote); } when (contains($name,"'")) { call write-text(name := substring-before($name,"'"), normalize-space := $normalize-space, quote:=$quote); value-of ("'"); call write-text(name := substring-after($name,"'"), normalize-space := $normalize-space, quote:=$quote); } when (contains($name,' ')) { call write-text(name := substring-before($name,' '), normalize-space := $normalize-space, quote:=$quote); value-of ('&#xA;'); call write-text(name := substring-after($name,' '), normalize-space := $normalize-space, quote:=$quote); } when (contains($name,' ')) { call write-text(name := substring-before($name,' '), normalize-space := $normalize-space, quote:=$quote); value-of ('&#xD;'); call write-text(name := substring-after($name,' '), normalize-space := $normalize-space, quote:=$quote); } when ($normalize-space) { call write-text-chars(text := normalize-space($name)); } otherwise { call write-text-chars(text := $name); } } } template write-text-chars(text) { variable printable-chars := " !#$%()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; variable non-printable := translate($text, $printable-chars,""); if ($non-printable = "") { value-of ($text); } else { variable length := string-length($text); if ($length > 1) { variable first-half := floor($length div 2); call write-text-chars(text:=substring($text, 1, $first-half)); call write-text-chars(text:=substring($text, $first-half+1, $length - $first-half)); } else { call write-text-char(char:=$text); } } } template write-text-char(char) { variable utf-8-chars := concat( -- excludes #x00 to #x1F, and " at #x22 " ! #$%&'()*+,-./", "0123456789:;<=>?", "@ABCDEFGHIJKLMNO", "PQRSTUVWXYZ[\]^_", "`abcdefghijklmno", "pqrstuvwxyz{|}~", "€‚ƒ„…†‡ˆ‰Š‹ŒŽ", "‘’“”•–—˜™š›œžŸ", " ¡¢£¤¥¦§¨©ª«¬­®¯", "°±²³´µ¶·¸¹º»¼½¾¿", "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ", "ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß", "àáâãäåæçèéêëìíîï", "ðñòóôõö÷øùúûüýþÿ"); if (contains($utf-8-chars, $char)) { variable code-point := 32 + string-length(substring-before($utf-8-chars, $char)); value-of ('&#'); value-of ($code-point); value-of (';'); } else { message "XSL2NiceXSL: string-to-codepoints() from XSLT 2 needed for non 8-bit character."; value-of ('&#9999;'); } } template write-xpath(name, no-punct := false(), no-space := false()) { if (not($no-punct) and not($no-space)) { value-of (' '); } if (not($no-punct)) { value-of ('('); } variable length := string-length($name); if ($length >= 2) { variable first-char := substring($name, 1, 1); variable middle-chars := substring($name, 2, $length - 2); variable last-char := substring($name, $length, 1); if ($first-char="'") { if ($last-char="'") { value-of ("'"); call write-text(name := $middle-chars, normalize-space:=false(), quote:="'"); value-of ("'"); } } else if ($first-char='"') { if ($last-char='"') { value-of ('"'); call write-text(name := $middle-chars, normalize-space:=false(), quote:='"'); value-of ('"'); } } else { call write-text(name := $name, normalize-space:=false()); } } else { call write-text(name := $name, normalize-space:=false()); } if (not($no-punct)) { value-of (')'); } } match (xsl:copy | xsl:decimal-format | xsl:document | xsl:fallback | xsl:import-schema | xsl:matching-substring | xsl:message | xsl:non-matching-substring | xsl:number | xsl:text) { call write-keyword(); call write-attributes(); call write-nodes(); } match (xsl:apply-templates) { call write-keyword(); if (@mode) { call write-name(name := @mode); } call write-xpath(name := @select); if (xsl:with-param) { call write-parameters(parameters := xsl:with-param); } call write-attributes(except1 := 'select', except2 := 'mode'); call write-nodes(except := 'xsl:with-param'); } match (xsl:choose) { if (not (@*) and count(node())=2 and xsl:when and xsl:otherwise) { for-each (xsl:when) { call write-keyword(name:='if'); call write-attributes(xpath1 := 'test'); call write-nodes(); } apply-templates (xsl:otherwise); } else { call write-keyword(); call write-attributes(); call write-nodes(); } } match (xsl:otherwise) { if (count(../node())=2 and ../xsl:when) { call write-keyword(name:='else'); if (count(node())=1 and count(xsl:choose/node())=2 and xsl:choose/xsl:when and xsl:choose/xsl:otherwise) { for-each (xsl:choose/xsl:when) { value-of (' if'); call write-attributes(xpath1 := 'test'); call write-nodes(); } apply-templates (xsl:choose/xsl:otherwise); } else { call write-attributes(); call write-nodes(); } } else { call write-keyword(); call write-attributes(); call write-nodes(); } } match (xsl:attribute-set | xsl:character-map) { call write-keyword(); call write-attributes(name1 := 'name'); call write-nodes(); } match (xsl:attribute) { if (@name and @type and @select and not(@*[4]) and not(node())) { value-of(' @'); call write-name(name := @name, prefix:=''); value-of(' :'); call write-name(name := @type); value-of(' := '); call write-xpath(name := @select, no-punct := true()); value-of(';'); } else if (@name and @select and not(@*[3]) and not(node())) { value-of(' @'); call write-name(name := @name, prefix:=''); value-of(':='); call write-xpath(name := @select, no-punct := true()); value-of(';'); } else if (@name and @type and not(@*[3]) and xsl:value-of[@select and not(node())] and not(node()[2])) { value-of(' @'); call write-name(name := @name, prefix:=''); value-of(' :'); call write-name(name := @type); value-of(' := '); call write-xpath(name := xsl:value-of/@select, no-punct := true()); value-of(';'); } else if (@name and not(@*[2]) and xsl:value-of[@select and not(node())] and not(node()[2])) { value-of(' @'); call write-name(name := @name, prefix:=''); value-of(':='); call write-xpath(name := xsl:value-of/@select, no-punct := true()); value-of(';'); } else { call write-keyword(); call write-attributes(name1 := 'name'); call write-nodes(); } } match (xsl:call-template) { call write-keyword(name := 'call'); call write-name(name := @name); call write-parameters(parameters := xsl:with-param); call write-attributes(except1 := 'name'); call write-nodes(except := 'xsl:with-param'); } match (xsl:copy-of | xsl:for-each | xsl:for-each-group | xsl:perform-sort | xsl:sequence | xsl:sort) { call write-keyword(); call write-attributes(xpath1 := 'select'); call write-nodes(); } match (xsl:function) { if (preceding-sibling::node()[1][node()]) { value-of (' '); } call write-keyword(name := 'function'); call write-name(name := @name); call write-parameters(parameters := xsl:param); call write-attributes(except1 := 'name', type1 := 'as'); call write-nodes(except := 'xsl:param'); } match (xsl:if | xsl:when) { call write-keyword(); call write-attributes(xpath1 := 'test'); call write-nodes(); } match (xsl:import | xsl:include) { call write-keyword(); call write-attributes(quoted1 := 'href'); call write-nodes(); } match (xsl:analyze-string) { call write-keyword(); value-of (' ('); call write-xpath(name := @select, no-punct:=true()); value-of (', "'); call write-xpath(name := @regex, no-punct:=true()); value-of ('")'); call write-attributes(except1 := 'select', except2 := 'regex'); call write-nodes(); } match (xsl:apply-imports) { call write-keyword(); call write-parameters(parameters := xsl:with-param); call write-attributes(except1 := 'name'); call write-nodes(except := 'xsl:with-param'); } match (xsl:comment) { call write-keyword(); call write-attributes(xpath1 := 'select'); call write-nodes(); } match (xsl:element) { call write-keyword(); call write-attributes(name1 := 'name'); call write-nodes(); } match (xsl:key) { call write-keyword(); call write-attributes(name1 := 'name', xpath1 := 'match'); call write-nodes(); } match (xsl:namespace) { call write-keyword(); if (@name = "") { value-of (' ""'); } else { call write-name(name := @name); } if (@select) { value-of(' = '); call write-quoted(name := @select); } call write-attributes(except1 := 'name', except2 := 'select'); call write-nodes(); } match (xsl:namespace-alias) { call write-keyword(); call write-attributes(quoted1 := 'stylesheet-prefix', quoted2 := 'result-prefix'); call write-nodes(); } match (xsl:next-match) { call write-keyword(); call write-parameters(parameters := xsl:with-param); call write-attributes(except1 := 'name'); call write-nodes(except := 'xsl:with-param'); } match (xsl:output-character) { call write-keyword(); call write-attributes(text1 := 'character', text2 := 'string'); call write-nodes(); } match (xsl:output) { call write-keyword(); if (not(@method)) { value-of(' ""'); } call write-attributes(name1 := 'method'); call write-nodes(); } match (xsl:preserve-space | xsl:strip-space) { call write-keyword(); call write-attributes(name1 := 'elements'); call write-nodes(); } match (xsl:processing-instruction) { call write-keyword(); call write-attributes(name1 := 'name', xpath1 := 'select'); call write-nodes(); } match (xsl:result-document) { call write-keyword(); if (not(@href)) { value-of(' ""'); } call write-attributes(quoted1 := 'href'); call write-nodes(); } match (xsl:stylesheet | xsl:transform) { call write-keyword(); if (xsl:param) { call write-parameters(parameters := xsl:param); } call write-attributes(); for-each (namespace::*[name() !='xml'and name() !='xsl']) { call write-namespace(); } call write-nodes(except := 'xsl:param'); } match (xsl:template) { if (preceding-sibling::node()[1][node()]) { value-of (' '); } if (@match) { call write-keyword(name := 'match'); if (@mode) { call write-name(name := @mode); } call write-xpath(name := @match, no-space := true()); if (xsl:param or @name) { if (@name) { call write-name(name := @name, prefix := ' | '); } call write-parameters(parameters := xsl:param); } call write-attributes(except1 := 'match', except2 := 'mode', except3 := 'name', type1 := 'as'); call write-nodes(except := 'xsl:param'); } else { call write-keyword(name := 'template'); call write-name(name := @name); call write-parameters(parameters := xsl:param); call write-attributes(except1 := 'name', type1 := 'as'); call write-nodes(except := 'xsl:param'); } } match (xsl:value-of) { call write-keyword(); call write-attributes(xpath1 := 'select'); call write-nodes(); } match (xsl:variable) { call write-keyword(); if (@name and @as and @select and not(@*[4]) and not(node())) { call write-name(name := @name); value-of(' :'); call write-name(name := @as); value-of(' := '); call write-xpath(name := @select, no-punct := true()); call write-nodes(); } else if (@name and @select and not(@*[3]) and not(node())) { call write-name(name := @name); value-of (' := '); call write-xpath(name := @select, no-punct := true()); call write-nodes(); } else if (@name and not(@*[2]) and node()) { call write-name(name := @name); value-of (' := '); call write-nodes(); value-of (';'); } else { call write-attributes(name1 := 'name', type1 := 'as', quoted2:='select'); call write-nodes(); } } match (/) { value-of (' '); apply-templates (@*); apply-templates (node()); -- apply-templates (text()); value-of (' '); } match (text()) { if (parent::xsl:text) { value-of (' "'); } else { call write-keyword(name := '"'); } call write-text(name := ., normalize-space := false(), quote:='"'); value-of ('"'); } match (comment()) { if (following-sibling::node()[1][self::xsl:template or self::xsl:function]) { value-of (' '); } call write-keyword(); value-of (''); } match (@*) { call write-attribute(); } match (xsl:*) { message { "XSL2NiceXSL: No match for construct." value-of (name()); } call write-keyword(name := concat('<', name())); call write-attributes(); call write-nodes(no-punct := true()); call write-keyword(name := '>'); } match (*) { call write-keyword(name := concat('<', name())); call write-attributes(); call write-nodes(no-punct := true()); if (count(node()) = count(xsl:attribute)) { value-of('>'); } else { call write-keyword(name := '>'); } } }