<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.w3.org/ns/xproc-step" xmlns:c="http://www.w3.org/ns/xproc-step" exclude-result-prefixes="#all" version="2.0" xpath-default-namespace="http://www.w3.org/ns/xproc-step"> <xsl:variable name="NameStartChar" select="':A-Z_a-zÀ-ÖØ-öø-˿Ͱ-ͽͿ-῿‌-‍⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-󯿿'"/> <xsl:variable name="NameChar" select="concat($NameStartChar,'\-\.0-9·̀-ͯ‿-⁀')"/> <xsl:variable name="PubidCharNoApos" select="' a-zA-Z0-9\-\(\)\+,\./:=\?;!\*#@\$_%'"/> <xsl:variable name="PubidChar" select="concat($PubidCharNoApos,'''')"/> <xsl:variable name="Name" select="concat('[',$NameStartChar,'][',$NameChar,']*')"/> <xsl:variable name="S" select="'[ ]+'"/> <xsl:variable name="SystemLiteral" select="'("[^"]*"|''[^'']*'')'"/> <xsl:variable name="PubidLiteral" select="concat('("[',$PubidChar,']*"|''[',$PubidCharNoApos,']*'')')"/> <xsl:template match="/*"> <c:result> <xsl:attribute name="xml:space" select="'preserve'"/> <xsl:text> </xsl:text> <xsl:variable name="bom"> <xsl:if test="@bom-type"> <xsl:text> </xsl:text> <c:bom type="{@bom-type}"> <xsl:if test="@bom-base64"> <xsl:attribute name="base64" select="@bom-base64"/> </xsl:if> <xsl:if test="@bom-hex"> <xsl:attribute name="hex" select="@bom-hex"/> </xsl:if> </c:bom> <xsl:text> </xsl:text> </xsl:if> </xsl:variable> <xsl:variable name="result"> <xsl:analyze-string select="text()" regex="<[?!][^>]*>[^<]*"> <xsl:matching-substring> <xsl:choose> <xsl:when test="starts-with(.,'<?')"> <c:processing-instruction> <xsl:value-of select="replace(.,'\s+$','')"/> </c:processing-instruction> </xsl:when> <xsl:when test="starts-with(.,'<!--')"> <c:comment> <xsl:value-of select="replace(.,'\s+$','')"/> </c:comment> </xsl:when> <xsl:otherwise> <c:doctype> <xsl:if test="upper-case(substring(.,1,9))='<!DOCTYPE'"> <xsl:attribute name="doctype-start" select="'true'"/> </xsl:if> <xsl:value-of select="."/> </c:doctype> </xsl:otherwise> </xsl:choose> </xsl:matching-substring> <xsl:non-matching-substring> <xsl:choose> <xsl:when test="contains(.,'<')"> <xsl:variable name="before-root-element" select="substring-before(.,'<')"/> <xsl:if test="$before-root-element"> <c:other> <xsl:value-of select="$before-root-element"/> </c:other> </xsl:if> <c:root-element> <xsl:value-of select="concat('<',replace(substring-after(.,'<'),'>[^>]*$','>'))"/> </c:root-element> </xsl:when> <xsl:when test="normalize-space(.)"> <c:other> <xsl:value-of select="."/> </c:other> </xsl:when> </xsl:choose> </xsl:non-matching-substring> </xsl:analyze-string> </xsl:variable> <xsl:variable name="result"> <xsl:for-each-group select="$result/*" group-adjacent="self::c:doctype or self::c:other and preceding-sibling::*[not(self::c:other)][1]/self::c:doctype"> <xsl:choose> <xsl:when test="current-grouping-key()"> <xsl:for-each-group select="current-group()" group-starting-with="c:doctype[@doctype-start='true']"> <c:doctype> <xsl:copy-of select="current-group()"/> </c:doctype> </xsl:for-each-group> </xsl:when> <xsl:otherwise> <xsl:for-each-group select="current-group()" group-adjacent="self::c:comment or self::c:other and preceding-sibling::*[not(self::c:other)][1]/self::c:comment"> <xsl:choose> <xsl:when test="current-grouping-key()"> <xsl:for-each-group select="current-group()" group-starting-with="c:comment[starts-with(.,'<!--')]"> <c:comment> <xsl:copy-of select="current-group()"/> </c:comment> </xsl:for-each-group> </xsl:when> <xsl:otherwise> <xsl:copy-of select="current-group()"/> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:variable> <xsl:variable name="result"> <xsl:for-each select="$result/*"> <xsl:choose> <xsl:when test="self::c:other and position() = 1"> <c:bom> <xsl:copy-of select="$bom/*/@*"/> <xsl:value-of select="."/> </c:bom> </xsl:when> <xsl:when test="self::c:processing-instruction"> <xsl:element name="c:{replace(text(),concat('^<\?(',$Name,')(',$S,'|\?).*$'),'$1','s')}"> <xsl:analyze-string select="text()" regex="{concat($Name,'\s*=\s*("[^"]*"|''[^'']*'')')}"> <xsl:matching-substring> <xsl:attribute name="{tokenize(.,'=')[1]}" select="replace(replace(.,concat($Name,'\s*=\s*("[^"]*"|''[^'']*'')'),'$1'),'^.(.*).$','$1','s')"/> </xsl:matching-substring> </xsl:analyze-string> <xsl:copy-of select="text()"/> </xsl:element> </xsl:when> <xsl:when test="self::c:doctype"> <xsl:copy> <xsl:variable name="doctype" select="replace(string-join(*/text(),''),'\s+$','','s')"/> <xsl:attribute name="name" select="replace($doctype,concat('<!DOCTYPE',$S,'(',$Name,')','[\s>].*'),'$1','s')"/> <xsl:variable name="public" select="if (matches($doctype,concat('^<!DOCTYPE',$S,$Name,$S,'PUBLIC',$S,$PubidLiteral,$S,$SystemLiteral,'.*$'))) then replace(replace($doctype,concat('^<!DOCTYPE',$S,$Name,$S,'PUBLIC',$S,'(',$PubidLiteral,')',$S,'.*$'),'$1'),'^.(.*).$','$1') else ()"/> <xsl:variable name="system" select="if (matches($doctype,concat('^<!DOCTYPE',$S,$Name,$S,'PUBLIC',$S,$PubidLiteral,$S,$SystemLiteral,'.*$'))) then replace(replace($doctype,concat('^<!DOCTYPE',$S,$Name,$S,'PUBLIC',$S,$PubidLiteral,$S,'(',$SystemLiteral,')(',$S,'|\[|>).*$'),'$2'),'^.(.*).$','$1') else ()"/> <xsl:variable name="system" select="if (not($system) and matches($doctype,concat('^<!DOCTYPE',$S,$Name,$S,'SYSTEM',$S,$SystemLiteral,'.*$'))) then replace(replace($doctype,concat('^<!DOCTYPE',$S,$Name,$S,'SYSTEM',$S,'(',$SystemLiteral,')(',$S,'|\[|>).*$'),'$1'),'^.(.*).$','$1') else $system"/> <xsl:variable name="internal" select="if (contains($doctype,'[')) then replace($doctype,'^[^\[]*\[\s*(.*?)\s*\][^\]]*$','$1','s') else ()"/> <xsl:if test="$public"> <xsl:attribute name="public" select="$public"/> </xsl:if> <xsl:if test="$system"> <xsl:attribute name="system" select="$system"/> </xsl:if> <xsl:if test="$internal or $internal=''"> <xsl:attribute name="internal" select="$internal"/> </xsl:if> <xsl:value-of select="$doctype"/> </xsl:copy> </xsl:when> <xsl:when test="self::c:comment"> <xsl:copy> <xsl:variable name="comment" select="string-join(*/text(),'')"/> <xsl:attribute name="text" select="substring-after(substring-before($comment,'-->'),'<!--')"/> <xsl:value-of select="$comment"/> </xsl:copy> </xsl:when> <xsl:otherwise> <xsl:copy-of select="."/> </xsl:otherwise> </xsl:choose> </xsl:for-each> </xsl:variable> <xsl:if test="not($result/c:bom and $bom)"> <xsl:copy-of select="$bom"/> </xsl:if> <xsl:for-each select="$result/*"> <xsl:text> </xsl:text> <xsl:copy-of select="."/> <xsl:text> </xsl:text> </xsl:for-each> </c:result> </xsl:template> </xsl:stylesheet>