我是XSLT的新手,但我正在尝试通过XSLT获取XML文件以显示某个节点集。我正在使用XSL 1.0。 xml看起来像这样:
<...>
<entry>
<organizer>
<component>
<observation>
<code displayName="Weight" />
<effectiveTime value="5/21/2013 12:00:00 AM" />
<value value="75" unit="lbs" />
</observation>
</component>
</organizer>
</entry>
<entry>
<organizer>
<component>
<observation>
<code displayName="BMI" />
<effectiveTime value="5/21/2013 12:00:00 AM" />
<value value="14.6" unit="98" />
</observation>
</component>
</organizer>
</entry>
<entry>
<organizer>
<component>
<observation>
<code displayName="Weight" />
<effectiveTime value="5/20/2013 12:00:00 AM" />
<value value="255" unit="lbs" />
</observation>
</component>
</organizer>
</entry>
<entry>
<organizer>
<component>
<observation>
<code displayName="BMI" />
<effectiveTime value="5/20/2013 12:00:00 AM" />
<value value="49.8" unit="98" />
</observation>
</component>
</organizer>
</entry>
<entry>
<organizer>
<component>
<observation>
<code displayName="Blood Pressure" />
<effectiveTime value="5/20/2013 12:00:00 AM" />
<value value="100/76" unit="mm Hg" />
</observation>
</component>
</organizer>
</entry>
</...>
我希望输出看起来像这样:
<table>
<tr>
<td>5/21/2013</td>
<td> </td>
<td>Weight: 75lbs</td>
<td>BMI: 14.6 90</td>
</tr>
<tr>
<td>5/20/2013</td>
<td>Blood Pressure: 100/76 mm Hg</td>
<td>Weight: 255lbs</td>
<td>BMI: 49.8 90</td>
</tr>
</table>
基本上,按有效时间(在观察节点内)分组,并将血压,体重和bmi放在后续列中。如果特定日期的特定代码显示名称不存在,我还需要一个空白表格单元格(请参阅第一次日期未列出的血压)。
感谢您的帮助。我正在接受XSLT,但由于有这么多,所以需要时间。
答案 0 :(得分:1)
你没有说哪个版本的XSLT,所以我假设2.0:
T:\ftemp>type entries.xml
<entries>
<entry>
<organizer>
<component>
<observation>
<code displayName="Weight" />
<effectiveTime value="5/21/2013 12:00:00 AM" />
<value value="75" unit="lbs" />
</observation>
</component>
</organizer>
</entry>
<entry>
<organizer>
<component>
<observation>
<code displayName="BMI" />
<effectiveTime value="5/21/2013 12:00:00 AM" />
<value value="14.6" unit="98" />
</observation>
</component>
</organizer>
</entry>
<entry>
<organizer>
<component>
<observation>
<code displayName="Weight" />
<effectiveTime value="5/20/2013 12:00:00 AM" />
<value value="255" unit="lbs" />
</observation>
</component>
</organizer>
</entry>
<entry>
<organizer>
<component>
<observation>
<code displayName="BMI" />
<effectiveTime value="5/20/2013 12:00:00 AM" />
<value value="49.8" unit="98" />
</observation>
</component>
</organizer>
</entry>
<entry>
<organizer>
<component>
<observation>
<code displayName="Blood Pressure" />
<effectiveTime value="5/20/2013 12:00:00 AM" />
<value value="100/76" unit="mm Hg" />
</observation>
</component>
</organizer>
</entry>
</entries>
T:\ftemp>call xslt2 entries.xml entries.xsl
<table>
<tr>
<td>5/21/2013</td>
<td> </td>
<td>Weight: 75 lbs</td>
<td>BMI: 14.6 98</td>
</tr>
<tr>
<td>5/20/2013</td>
<td>Blood Pressure: 100/76 mm Hg</td>
<td>Weight: 255 lbs</td>
<td>BMI: 49.8 98</td>
</tr>
</table>
T:\ftemp>type entries.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="html"/>
<xsl:template match="entries">
<!--dictate the order of the columns this way-->
<xsl:variable name="fields" select="('Blood Pressure','Weight','BMI')"/>
<!--create the table-->
<table>
<!--grouped by time-->
<xsl:for-each-group select="entry"
group-by="organizer/component/observation/effectiveTime/@value">
<tr>
<!--subset of time-->
<td>
<xsl:value-of select="substring-before(
organizer/component/observation/effectiveTime/@value,' ')"/>
</td>
<!--the fields in order-->
<xsl:for-each select="$fields">
<xsl:variable name="this"
select="current-group()[organizer/component/observation/code/@displayName=
current()]/organizer/component/observation/value"/>
<xsl:choose>
<xsl:when test="$this">
<td>
<xsl:value-of
select="concat(.,': ',$this/@value,' ',$this/@unit)"/>
</td>
</xsl:when>
<xsl:otherwise><td> </td></xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</tr>
</xsl:for-each-group>
</table>
</xsl:template>
</xsl:stylesheet>
T:\ftemp>rem Done!
答案 1 :(得分:0)
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output method="html" indent="yes" />
<xsl:key name="kObservationByTime" match="observation" use="effectiveTime/@value" />
<xsl:template match="/">
<table>
<tr>
<th>Time</th>
<th>Blood Pressure</th>
<th>Weight</th>
<th>BMI</th>
</tr>
<xsl:apply-templates mode="group" select="
*//observation[
generate-id()
=
generate-id(key('kObservationByTime', effectiveTime/@value)[1])
][position() > last() - 3]
" />
<xsl:sort select="effectiveTime/@value" order="descending" />
</xsl:apply-templates>
</table>
</xsl:template>
<xsl:template match="observation" mode="group">
<xsl:variable name="time" select="effectiveTime/@value" />
<xsl:variable name="thisGroup" select="key('kObservationByTime', $time)" />
<tr>
<td><xsl:value-of select="substring-before($time, ' ')" /></td>
<td><xsl:apply-templates select="$thisGroup[code[@displayName = 'Blood Pressure']]" /></td>
<td><xsl:apply-templates select="$thisGroup[code[@displayName = 'Weight']]" /></td>
<td><xsl:apply-templates select="$thisGroup[code[@displayName = 'BMI']]" /></td>
</tr>
</xsl:template>
<xsl:template match="observation">
<xsl:value-of select="normalize-space(concat(value/@value, ' ', value/@unit))" />
</xsl:template>
</xsl:stylesheet>
给你
<table>
<tr>
<th>Time</th>
<th>Blood Pressure</th>
<th>Weight</th>
<th>BMI</th>
</tr>
<tr>
<td>5/21/2013</td>
<td></td>
<td>75 lbs</td>
<td>14.6 98</td>
</tr>
<tr>
<td>5/20/2013</td>
<td>100/76 mm Hg</td>
<td>255 lbs</td>
<td>49.8 98</td>
</tr>
</table>
http://www.xmlplayground.com/O9Z9DT
此解决方案使用<xsl:key>
进行分组。
[position() > last() - 3]
谓词选择最后2个组进行显示。替代方案[position() < 3]
将选择前两个。两者都按文档顺序工作,而<xsl:sort>
仅影响输出顺序。
请注意due to an unwise choice in date formatting,使用漂亮的代码无法明智地对结果进行排序。
按日期对条目进行排序的非漂亮代码如下所示:
<xsl:sort select="
concat(
substring-after(substring-after(substring-before(effectiveTime/@value, ' '), '/'), '/'),
'-',
10 + substring-before(effectiveTime/@value, '/'),
'-',
10 + substring-before(substring-after(effectiveTime/@value, '/'), '/')
)
" order="descending" />
...或者您只是使用合理的日期格式,痛苦就会消失。 ;)
答案 2 :(得分:0)
以下是使用XSLT 1.0的解决方案版本...而不是使用字段名称变量,我为每个字符编码列处理。
T:\ftemp>type entries.xml
<entries>
<entry>
<organizer>
<component>
<observation>
<code displayName="Weight" />
<effectiveTime value="5/21/2013 12:00:00 AM" />
<value value="75" unit="lbs" />
</observation>
</component>
</organizer>
</entry>
<entry>
<organizer>
<component>
<observation>
<code displayName="BMI" />
<effectiveTime value="5/21/2013 12:00:00 AM" />
<value value="14.6" unit="98" />
</observation>
</component>
</organizer>
</entry>
<entry>
<organizer>
<component>
<observation>
<code displayName="Weight" />
<effectiveTime value="5/20/2013 12:00:00 AM" />
<value value="255" unit="lbs" />
</observation>
</component>
</organizer>
</entry>
<entry>
<organizer>
<component>
<observation>
<code displayName="BMI" />
<effectiveTime value="5/20/2013 12:00:00 AM" />
<value value="49.8" unit="98" />
</observation>
</component>
</organizer>
</entry>
<entry>
<organizer>
<component>
<observation>
<code displayName="Blood Pressure" />
<effectiveTime value="5/20/2013 12:00:00 AM" />
<value value="100/76" unit="mm Hg" />
</observation>
</component>
</organizer>
</entry>
</entries>
T:\ftemp>call xslt entries.xml entries1.xsl
<table>
<tr>
<td>5/21/2013</td>
<td> </td>
<td>Weight: 75 lbs</td>
<td>BMI: 14.6 98</td>
</tr>
<tr>
<td>5/20/2013</td>
<td>Blood Pressure: 100/76 mm Hg</td>
<td>Weight: 255 lbs</td>
<td>BMI: 49.8 98</td>
</tr>
</table>
T:\ftemp>type entries1.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html"/>
<xsl:key name="times" match="entry"
use="organizer/component/observation/effectiveTime/@value"/>
<xsl:template match="entries">
<!--create the table-->
<table>
<!--grouped by time-->
<xsl:for-each select="entry[generate-id(.)=
generate-id(key('times',
organizer/component/observation/effectiveTime/@value)[1])]">
<tr>
<!--subset of time-->
<td>
<xsl:value-of select="substring-before(
organizer/component/observation/effectiveTime/@value,' ')"/>
</td>
<!--the fields in order-->
<xsl:variable name="values"
select="key('times',
organizer/component/observation/effectiveTime/@value)/
organizer/component/observation"/>
<xsl:choose>
<xsl:when test="$values/code[@displayName='Blood Pressure']">
<td>
<xsl:for-each
select="$values[code/@displayName='Blood Pressure']">
<xsl:value-of
select="concat('Blood Pressure: ',value/@value,' ',value/@unit)"/>
</xsl:for-each>
</td>
</xsl:when>
<xsl:otherwise><td> </td></xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="$values/code[@displayName='Weight']">
<td>
<xsl:for-each
select="$values[code/@displayName='Weight']">
<xsl:value-of
select="concat('Weight: ',value/@value,' ',value/@unit)"/>
</xsl:for-each>
</td>
</xsl:when>
<xsl:otherwise><td> </td></xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="$values/code[@displayName='BMI']">
<td>
<xsl:for-each
select="$values[code/@displayName='BMI']">
<xsl:value-of
select="concat('BMI: ',value/@value,' ',value/@unit)"/>
</xsl:for-each>
</td>
</xsl:when>
<xsl:otherwise><td> </td></xsl:otherwise>
</xsl:choose>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
T:\ftemp>rem Done!