我是XSL和XPath的新手。抱歉,如果这个问题显示出一些愚蠢。
我有一个类似
的XML<root>
<widget name="status">
...
<component name="date">
<component name="day" label="Fri"/>
<component name="date" label="4"/>
</component>
<component name="time" label="11:23 AM"/>
....
</widget>
<widget name="foo">
</widget>
</root>
我需要创建一个DateTime标记,它由所有三个值组成 周五上午11:23
我正在为它写一个XSL。
<DateTime>
<xsl:value-of select="(//widget[@name="status"]/component[@name='date'])[1]/@label"/>
<xsl:text> </xsl:text>
<xsl:value-of select="(//widget[@name="status"]/component[@name='date'])[2]/@label"/>
<xsl:text> </xsl:text>
<xsl:value-of select="//widget[@name="status"]/component[@name='time']/@label"/>
</DateTime>
问题:
我将“widget [@ name =”date“]”传递给每个select语句。有没有更好的方法来缩短xpath。
我需要将其移动到模板中并调用模板。哪一个我应该使用call-template / apply-templates?
我们有一组生成这些XML的类似应用程序。上面的XML来自applicationA。 ApplicationB可能会以稍微不同的方式显示细节,例如<component name="datetime">Fri 4 11:23 AM</component>
。我们有近3-4个这样的应用程序,它们以稍微不同的方式显示细节。
DateTime只是一个例子,我还需要从这些不同的应用程序中捕获一些其他细节。
我正在考虑编写一个XSL来处理所有应用程序。
答案 0 :(得分:1)
使用XML执行此操作的一种方法是:
<xsl:template match="widget">
<!-- ... -->
<xsl:apply-templates select="." mode="create-date-time" />
<!-- ... -->
</xsl:template>
<xsl:template match="widget" mode="create-date-time">
<xsl:variable name="date" select="component[@name='date']" />
<xsl:variable name="time" select="component[@name='time']" />
<DateTime>
<xsl:value-of select="normalize-space(
concat(
$date/component[@name='day']/@label, ' ',
$date/component[@name='date']/@label, ' ',
$time/@label
)
)" />
</DateTime>
</xsl:template>
- 我将
widget[@name="date"]
传递给每个select语句。有没有更好的方法来缩短xpath。
使用<xsl:template>
/ <xsl:apply-templates>
和相对路径。在<xsl:variable>
中多次存储您需要的内容。见上文。
- 我需要将其移动到模板中并调用模板。哪一个我应该使用call-template / apply-templates?
后者。总是去<xsl:apply-templates>
,除非有充分理由不这样做。根据经验:如果你不确定,那就没有充分的理由。
- 我们有一组生成这些XML的类似应用程序。上面的XML来自applicationA。 ApplicationB可能会以稍微不同的方式显示细节,例如
<component name="datetime">Fri 4 11:23 AM</component>
我们有近3-4个这样的应用程序,它们以稍微不同的方式显示细节。
您可以展开create-date-time
模板以适应此目的:
<xsl:template match="widget" mode="create-date-time">
<xsl:variable name="date" select="component[@name='date']" />
<xsl:variable name="time" select="component[@name='time']" />
<xsl:variable name="dt" select="component[@name='datetime']" />
<DateTime>
<xsl:value-of select="normalize-space(
concat(
$dt/label, ' ',
$date/component[@name='day']/@label, ' ',
$date/component[@name='date']/@label, ' ',
$time/@label
)
)" />
</DateTime>
</xsl:template>
如果缺少某些组件,则不会出错。 normalize-space()
确保任何组件组合都没有多余的空格。
如果date
+ time
和datetime
组件不相互排斥(我假设它们是),则上述情况可能会失败。如果不是,或者如果出现更复杂的情况,请创建其他特定模板,如下所示:
<xsl:template match="widget[component[name='datetime']]" mode="create-date-time">
<xsl:variable name="dt" select="component[@name='datetime']" />
<DateTime>
<xsl:value-of select="component[@name='datetime']/@label" />
</DateTime>
</xsl:template>
<xsl:apply-templates>
将确保调用正确的一个。只需为每个可能发生的案例创建特定的match=
表达式。
答案 1 :(得分:0)
这个简单的转换(16行,单个模板,完全“推”式,无变量,无模式):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match=
"component
[contains('|day|date|time|',
concat('|', @name, '|'))
]
">
<xsl:value-of select="concat(@label, ' ')"/>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
应用于提供的XML文档:
<root>
<widget name="status">
...
<component name="date">
<component name="day" label="Fri"/>
<component name="date" label="4"/>
</component>
<component name="time" label="11:23 AM"/>
....
</widget>
<widget name="foo">
</widget>
</root>
产生完全想要的结果:
Fri 4 11:23 AM