我是XSLT的新手,我正在尝试转换以下XML:
<array>
<!-- red herring -->
<Telop ID="t01">
<time>0</time>
<Sentence />
</Telop>
<!-- start time and label -->
<Telop ID="t02">
<time>14</time>
<Sentence>Subtitle 1</Sentence>
</Telop>
<!-- end time -->
<Telop ID="t03">
<time>26</time>
<Sentence />
</Telop>
<!-- start time and label -->
<Telop ID="t04">
<time>44</time>
<Sentence>Subtitle 2</Sentence>
</Telop>
<!-- end time -->
<Telop ID="t05">
<time>48</time>
<Sentence />
</Telop>
</array>
进入以下结构,其中备用节点提供开始时间和标签,紧接着的兄弟提供结束时间:
<div>
<p begin="00:00:14.000" end="00:00:26.000">Subtitle 1</p>
<p begin="00:00:44.000" end="00:00:48.000">Subtitle 2</p>
</div>
我拼凑了以下内容:
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<div xml:lang="en" style="1">
<xsl:for-each select="array/Telop">
<xsl:if test="not(position() mod 2)">
<p>
<xsl:attribute name="begin">
<xsl:value-of select="time" />
</xsl:attribute>
<xsl:attribute name="end">
<!-- How can I get the time from the immediate following sibling? -->
<xsl:value-of select="/following-sibling::time" />
</xsl:attribute>
<xsl:value-of select="Sentence" />
</p>
</xsl:if>
</xsl:for-each>
</div>
</xsl:template>
这非常接近,但我无法弄清楚如何为后续兄弟提取时间值。
答案 0 :(得分:3)
这个XSLT应该可以胜任。
我冒昧或删除了“xslt:for-each”(被认为是ucky)和“xslt:if”(可以合并)
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/array">
<div xml:lang="en" style="1">
<xsl:apply-templates select="Telop[not(position() mod 2)]" />
</div>
</xsl:template>
<xsl:template match="Telop">
<p>
<xsl:attribute name="begin">
<xsl:value-of select="time" />
</xsl:attribute>
<xsl:attribute name="end">
<xsl:value-of select="following-sibling::Telop[1]/time" />
</xsl:attribute>
<xsl:value-of select="Sentence" />
</p>
</xsl:template>
</xsl:transform>
希望这有帮助,
答案 1 :(得分:1)
这是一种略有不同的方法,因为它不依赖于position()
的模2。相反,这一行
<xsl:for-each select="Telop[Sentence/text()]">
检查Sentence
是否包含文字。至于xsl:for-each的丑陋,这是事实,但它确实起到了作用。
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="array">
<xsl:element name="div">
<xsl:for-each select="Telop[Sentence/text()]">
<xsl:element name="p">
<xsl:attribute name="begin">
<xsl:value-of select="./time"/>
</xsl:attribute>
<xsl:attribute name="end">
<xsl:value-of select="following-sibling::Telop[1]/time"/>
</xsl:attribute>
<xsl:value-of select="Sentence"/>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
答案 2 :(得分:0)
我确定的解决方案(感谢Marvin和Mathias),并将秒值的格式设置为小时:分钟:秒(在此answer的帮助下)如下:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/array">
<tt xmlns="http://www.w3.org/ns/ttml" xmlns:tts="http://www.w3.org/ns/ttml#styling" xml:lang="en">
<head>
<styling>
<style tts:textOutline="black 1px 0px" tts:color="white" xml:id="1" tts:textAlign="center" tts:padding="0px" tts:fontSize="16px" tts:fontFamily="Arial, Helvetica, sans-serif"/>
</styling>
</head>
<body>
<div xml:lang="en" style="1">
<xsl:apply-templates select="Telop[not(position() mod 2)]" />
</div>
</body>
</tt>
</xsl:template>
<xsl:template match="Telop">
<xsl:element name="p">
<xsl:attribute name="begin">
<xsl:call-template name="format-time">
<xsl:with-param name="value" select="time" />
</xsl:call-template>
</xsl:attribute>
<xsl:attribute name="end">
<xsl:call-template name="format-time">
<xsl:with-param name="value" select="following-sibling::Telop[1]/time" />
</xsl:call-template>
</xsl:attribute>
<xsl:value-of select="Sentence" />
</xsl:element>
</xsl:template>
<xsl:template name="format-time">
<xsl:param name="value" select="." />
<xsl:param name="alwaysIncludeHours" select="true()" />
<xsl:param name="includeSeconds" select="true()" />
<xsl:if test="$value > 3600 or $alwaysIncludeHours">
<xsl:value-of select="concat(format-number($value div 3600, '00'), ':')"/>
</xsl:if>
<xsl:value-of select="format-number(floor($value div 60), '00')" />
<xsl:if test="$includeSeconds">
<xsl:value-of select="concat(':', format-number($value mod 60, '00'))" />
</xsl:if>
</xsl:template>
</xsl:transform>