Open timbrisc opened 1 year ago
This ticket is orphaned because text from the original trac site had been mass purged (to which I quite frankly disagree, nothing should have been mass purged).
Once the text is brought back, we can look at that. I might have done this XSLT stuff once a long time ago, but it was never an actual semantic implementation.
This refers to an implementation of a parser in XSLT which I did once a while ago. However, it never reached production stage. The motivation at that time was to create a set of tools to convert units as part of the "display process", i. e. converting some source to HTML without relying on XSLT-external code like Java.
Funny, I have done something like that while still at Regenstrief when some southern Indiana town was flooded and I whipped up some CDA EHR viewer XSLT. Let's see if I can still find that ... here is something you might try:
<xsl:transform version="2.0"
xmlns:saxon="http://saxon.sf.net/"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="f"
xmlns="urn:hl7-org:v3"
exclude-result-prefixes="f saxon xsl">
<xsl:variable name="ucum-essence" select="document('ucum-essence.xml')"/>
<xsl:variable name="prefix" select="$ucum-essence/*/prefix"/>
<xsl:variable name="metric-unit" select="$ucum-essence/*/base-unit|$ucum-essence/*/unit[@isMetric='yes']"/>
<xsl:variable name="non-metric-unit" select="$ucum-essence/*/unit[not(@isMetric='yes')]"/>
<xsl:variable name="prefix-regex" select="string-join($ucum-essence/*/prefix/@Code,'|')"/>
<xsl:variable name="metric-regex" select="replace(string-join($metric-unit/@Code,'|'),'([\[\]\*\^])','\\$1')"/>
<xsl:variable name="non-metric-regex" select="replace(string-join($non-metric-unit/@Code,'|'),'([\[\]\*\^])','\\$1')"/>
<xsl:function name="f:formatUnit" saxon:memo-function="yes">
<xsl:param name="code"/>
<xsl:if test="$code">
<xsl:analyze-string select="$code" regex="[/\.\(\)]">
<xsl:matching-substring>
<span class="unit-operator"><xsl:sequence select="if(.='.') then ' ' else ."/></span>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:sequence select="f:formatAnnot(.)"/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:if>
</xsl:function>
<xsl:function name="f:formatAnnot" saxon:memo-function="yes">
<xsl:param name="code"/>
<xsl:analyze-string select="$code" regex="{'\{([^\}]+)\}'}">
<xsl:matching-substring>
<span class="unit-annotation"><xsl:sequence select="regex-group(1)"/></span>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:sequence select="f:formatPart(.)"/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:function>
<xsl:function name="f:formatPart" saxon:memo-function="yes">
<xsl:param name="code"/>
<xsl:analyze-string select="$code" regex="^({$prefix-regex})?({$metric-regex})([0-9]*)$">
<xsl:matching-substring>
<span class="unit-prefix"><xsl:sequence select="($prefix[@Code=regex-group(1)]/printSymbol/node(), regex-group(1))[1]"/></span>
<xsl:variable name="printSymbol" select="$metric-unit[@Code=regex-group(2)]/printSymbol/node()"/>
<span class="unit-atom"><xsl:sequence select="if($printSymbol) then $printSymbol else f:formatAtom(regex-group(2))"/></span>
<xsl:if test="regex-group(3)">
<sup class="unit-exponent"><xsl:sequence select="regex-group(3)"/></sup>
</xsl:if>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:sequence select="f:formatNonMetric(.)"/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:function>
<xsl:function name="f:formatNonMetric" saxon:memo-function="yes">
<xsl:param name="code"/>
<xsl:analyze-string select="$code" regex="^({$non-metric-regex})([0-9]*)$">
<xsl:matching-substring>
<xsl:variable name="printSymbol" select="$non-metric-unit[@Code=regex-group(1)]/printSymbol/node()"/>
<span class="unit-atom"><xsl:sequence select="if($printSymbol) then $printSymbol else f:formatAtom(regex-group(1))"/></span>
<xsl:if test="regex-group(2)">
<sup class="unit-exponent"><xsl:sequence select="regex-group(2)"/></sup>
</xsl:if>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:sequence select="f:formatAtom(.)"/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:function>
<xsl:function name="f:formatAtom" saxon:memo-function="yes">
<xsl:param name="code"/>
<xsl:analyze-string select="$code" regex="^\[([^\]]+)\]$">
<xsl:matching-substring>
<span class="unit-bracket"><xsl:sequence select="f:formatSub(regex-group(1))"/></span>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:sequence select="f:formatSub(.)"/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:function>
<xsl:function name="f:formatSub" saxon:memo-function="yes">
<xsl:param name="code"/>
<xsl:analyze-string select="$code" regex="_(.+)$">
<xsl:matching-substring>
<sub class="unit-index"><xsl:sequence select="regex-group(1)"/></sub>
</xsl:matching-substring>
<xsl:non-matching-substring>
<span class="unit-remainder"><xsl:sequence select="."/></span>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:function>
</xsl:transform>
I called this the ucum-format-function.xsl and after xsl:import'ing that you can call f:formatUnit(@unit) and it will give you a pretty nice HTML with subscripts and superscripts, italics and all.
Issue migrated from trac ticket # 5828
component: help | priority: major
2022-08-03 14:23:40: Clinical.Terminology@mft.nhs.uk created the issue