我得到了一个XML,需要创建下面显示的表。如您所见,行中的结果需要映射列标题。这些标题列是动态的(取决于提供的时间戳(
Medi | A | B |
---|
我会这样做:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="data-by-time" match="EINZELDOSIS" use="ZEIT" />
<xsl:key name="data-by-cell" match="EINZELDOSIS" use="concat(ZEIT, '|', generate-id(..))" />
<xsl:variable name="distinct-times-RTF">
<xsl:for-each select="/XML_DATA/MRO_MEDIKAMENT/EINZELDOSIS[count(. | key('data-by-time', ZEIT)[1]) = 1]">
<xsl:sort select="ZEIT" data-type="text" order="ascending"/>
<xsl:copy-of select="ZEIT"/>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="distinct-times" select="exsl:node-set($distinct-times-RTF)/ZEIT" />
<xsl:variable name="source_document" select="/" />
<xsl:template match="/XML_DATA">
<table border="1">
<thead>
<tr>
<th>Medi</th>
<th>Einh</th>
<th>Dosis</th>
<!-- a column header for each distinct time point -->
<xsl:for-each select="$distinct-times">
<th>
<xsl:value-of select="."/>
</th>
</xsl:for-each>
</tr>
</thead>
<tbody>
<xsl:for-each select="MRO_MEDIKAMENT">
<xsl:variable name="row-id" select="generate-id()" />
<tr>
<td>
<xsl:value-of select="MEDI"/>
</td>
<td>
<xsl:value-of select="EINH"/>
</td>
<td>
<xsl:value-of select="DOSIS"/>
</td>
<!-- create a cell for each distinct time point -->
<xsl:for-each select="$distinct-times">
<xsl:variable name="zeit" select="." />
<td>
<!-- get matching data point -->
<!-- switch the context back to the source document -->
<xsl:for-each select="$source_document">
<xsl:value-of select="key('data-by-cell', concat($zeit, '|', $row-id))/DOSIS" />
</xsl:for-each>
</td>
</xsl:for-each>
</tr>
</xsl:for-each>
</tbody>
</table>
</xsl:template>
</xsl:stylesheet>
这将对所有提供的时间点执行Muenchian分组并对结果进行排序。接下来,为每个不同的时间点创建一个列标题。然后,在每一行中,我们为每个不同的时间点创建一个单元格,并用当前行和当前时间点的相应交叉点的数据填充它。
使用XSLT 3(目前在许多平台上由Saxon HE 10或11或SaxonJS 2支持(:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
expand-text="yes"
version="3.0">
<xsl:template match="XML_DATA">
<table>
<xsl:variable name="times" select="distinct-values(MRO_MEDIKAMENT/EINZELDOSIS/ZEIT) => sort()"/>
<thead>
<tr>
<xsl:apply-templates select="*[1]/(* except EINZELDOSIS), $times" mode="th"/>
</tr>
</thead>
<tbody>
<xsl:apply-templates>
<xsl:with-param name="times" select="$times" tunnel="yes"/>
</xsl:apply-templates>
</tbody>
</table>
</xsl:template>
<xsl:template match="*" mode="th">
<th>{local-name()}</th>
</xsl:template>
<xsl:template match="." mode="th">
<th>{.}</th>
</xsl:template>
<xsl:template match="MRO_MEDIKAMENT">
<xsl:param name="times" tunnel="yes"/>
<tr>
<xsl:apply-templates select="* except EINZELDOSIS, for $time in $times return (EINZELDOSIS[ZEIT = $time]/DOSIS, $time)[1]"/>
</tr>
</xsl:template>
<xsl:template match="MRO_MEDIKAMENT//*">
<td>{.}</td>
</xsl:template>
<xsl:template match=".[. instance of xs:untypedAtomic]">
<td></td>
</xsl:template>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="html" indent="yes" html-version="5"/>
<xsl:template match="/">
<html>
<head>
<title>Example</title>
</head>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
转换为XSLT1:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
xmlns:msxml="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="exsl msxml"
version="1.0">
<xsl:key name="time" match="ZEIT" use="."/>
<xsl:template match="XML_DATA">
<table>
<xsl:variable name="times-rtf">
<xsl:for-each select="MRO_MEDIKAMENT/EINZELDOSIS/ZEIT[generate-id() = generate-id(key('time', .)[1])]">
<xsl:sort select="."/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="times" select="exsl:node-set($times-rtf)/*"/>
<thead>
<tr>
<xsl:apply-templates select="*[1]/*[not(self::EINZELDOSIS)] | $times" mode="th"/>
</tr>
</thead>
<tbody>
<xsl:apply-templates>
<xsl:with-param name="times" select="$times"/>
</xsl:apply-templates>
</tbody>
</table>
</xsl:template>
<xsl:template match="*" mode="th">
<th>
<xsl:value-of select="local-name()"/>
</th>
</xsl:template>
<xsl:template match="ZEIT" mode="th">
<th>
<xsl:value-of select="."/>
</th>
</xsl:template>
<xsl:template match="MRO_MEDIKAMENT">
<xsl:param name="times"/>
<tr>
<xsl:apply-templates select="*[not(self::EINZELDOSIS)]"/>
<xsl:apply-templates select="$times">
<xsl:with-param name="med" select="current()"/>
</xsl:apply-templates>
</tr>
</xsl:template>
<xsl:template match="MRO_MEDIKAMENT//*">
<td>
<xsl:value-of select="."/>
</td>
</xsl:template>
<xsl:template match="ZEIT">
<xsl:param name="med"/>
<td>
<xsl:value-of select="$med/EINZELDOSIS[ZEIT = current()]/DOSIS"/>
</td>
</xsl:template>
<xsl:output method="html" indent="yes" version="5" doctype-system="about:legacy-doctype"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<html>
<head>
<title>Example</title>
</head>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
将稀疏属性值分布到列中可以使用XSLT1.0和一些EXSLT函数(EXSLT(,这里使用xmlstarlet。假设POSIX外壳、缩进和换行字符为了可读性而添加。
xmlstarlet select --text
--template
--var ofs -o "$(printf 't')" -b
--var ors -n -b
--var zeiten_rtf
-m 'set:distinct(//EINZELDOSIS/ZEIT)'
-s 'A:T:-' '.'
-e punkt -v '.' -b
-b
-b
--var zeiten='exslt:node-set($zeiten_rtf)/punkt'
-m 'str:split("Medi Einh Dosis") | $zeiten'
--if 'position() != 1' -v '$ofs' -b
-v '.'
-b
-v '$ors'
-m '/*/MRO_MEDIKAMENT'
--var med='.'
-v 'concat(MEDI,$ofs,EINH,$ofs,DOSIS)'
-m '$zeiten'
-v 'concat($ofs, $med/EINZELDOSIS[ ZEIT=current() ]/DOSIS)'
-b
-v '$ors'
-b
file.xml
- CCD_ 1和CCD_,分别(制表符和换行符(
- 提取一天中所有唯一的时间值(使用EXSLT函数
set:distinct
(,分类并存储在结果树片段(RTF(中,然后强制进入节点集使用EXSLT的node-set()
函数 - 标题行列出了固定字段(使用
str:split
(以及一天中的所有时间值 - 使用直接的XSLT1.0迭代项,输出一个空字符串如果列中不存在时间值
- 选项:CCD_ 6是CCD_ 7、CCD_,
-m
是ofs
0、-s
是xsl:sort
,CCD_ 13是CCD_,-e
为xsl:element
、--if
/--elif
为xsl:when
,ors
0标记块结束
输出(通过expand -t 8
输送时(:
Medi Einh Dosis 07:30 09:30 12:00 18:00 22:00
A Stk 1-0-1 1 0 1
B Stk 1-0-0-1 1 0 0 1
在--template
之前添加-C
选项会列出生成的XSLT样式表而不运行它:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:set="http://exslt.org/sets" xmlns:exslt="http://exslt.org/common" xmlns:str="http://exslt.org/strings" version="1.0" extension-element-prefixes="exslt set str">
<xsl:output omit-xml-declaration="yes" indent="no" method="text"/>
<xsl:template match="/">
<xsl:variable name="ofs">
<xsl:text> </xsl:text>
</xsl:variable>
<xsl:variable name="ors">
<xsl:value-of select="' '"/>
</xsl:variable>
<xsl:variable name="zeiten_rtf">
<xsl:for-each select="set:distinct(//EINZELDOSIS/ZEIT)">
<xsl:sort order="ascending" data-type="text" select="."/>
<xsl:element name="punkt">
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="."/>
</xsl:call-template>
</xsl:element>
</xsl:for-each>
</xsl:variable>
<xsl:variable select="exslt:node-set($zeiten_rtf)/punkt" name="zeiten"/>
<xsl:for-each select="str:split("Medi Einh Dosis") | $zeiten">
<xsl:choose>
<xsl:when test="position() != 1">
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="$ofs"/>
</xsl:call-template>
</xsl:when>
</xsl:choose>
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="."/>
</xsl:call-template>
</xsl:for-each>
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="$ors"/>
</xsl:call-template>
<xsl:for-each select="/*/MRO_MEDIKAMENT">
<xsl:variable select="." name="med"/>
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="concat(MEDI,$ofs,EINH,$ofs,DOSIS)"/>
</xsl:call-template>
<xsl:for-each select="$zeiten">
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="concat($ofs, $med/EINZELDOSIS[ ZEIT=current() ]/DOSIS)"/>
</xsl:call-template>
</xsl:for-each>
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="$ors"/>
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template name="value-of-template">
<xsl:param name="select"/>
<xsl:value-of select="$select"/>
<xsl:for-each select="exslt:node-set($select)[position()>1]">
<xsl:value-of select="' '"/>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>