在具有字符串长度条件的 XSLT 中将 XML 转换为 HTML
Transform XML to HTML in XSLT with string length condition
我有一个使用 TEI 构建的 XML 文件:
<div type="chapter" n="1">
<p>
<s xml:id="e_1">sentence e1.</s>
<s xml:id="f_1">sentence f1</s>
</p>
<p>
<s xml:id="e_2"> sentence e2</s>
<s xml:id="f_2"> sentence f2</s>
</p>
</div>
<div type="chapter" n="2">
<!-- -->
</div>
我需要将它转换成这个HTML结构:
<div>
<h1>Chapter 1</h1>
<div class="book-content">
<p>
<span class='source-language-sent' data-source-id='1'>sentence e1.</span>
<span id='1' style='display:none'>sentence f1</span>
</p>
<p>
<span class='source-language-sent' data-source-id='2'>sentence e2</span>
<span id='2' style='display:none'>sentence f2</span>
</p>
</div>
</div>
<div>
<h1>Chapter 2</h1>
<div class="book-content">
<!-- -->
</div>
</div>
现在我使用这个 XSLT 文件:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tei="http://www.tei-c.org/ns/1.0" version="1.0">
<xsl:output method="html" encoding="UTF-8" indent="yes" />
<xsl:template match="tei:body">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="tei:teiHeader">
<xsl:comment>
<xsl:apply-templates select="node()" />
</xsl:comment>
</xsl:template>
<!--create chapter-->
<xsl:template match="tei:div">
<xsl:element name="div">
<xsl:element name="div">
<xsl:attribute name="class">
<xsl:text>book-content</xsl:text>
</xsl:attribute>
<xsl:element name="h1">
<xsl:text>Chapter</xsl:text>
<xsl:value-of select="@n" />
</xsl:element>
<xsl:apply-templates select="node()" />
</xsl:element>
</xsl:element>
</xsl:template>
<!-- create p-->
<xsl:template match="tei:p">
<xsl:element name="p">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
<!-- create s-->
<xsl:template match="tei:s">
<xsl:variable name="xmlid" select="@xml:id" />
<xsl:if test="starts-with($xmlid, 'e')">
<xsl:element name="span">
<xsl:attribute name="class">
<xsl:text>source-language-sent</xsl:text>
</xsl:attribute>
<xsl:attribute name="data-source-id">
<xsl:value-of select="substring($xmlid, 3, 4)" />
</xsl:attribute>
<xsl:apply-templates select="node()" />
</xsl:element>
</xsl:if>
<xsl:if test="starts-with($xmlid, 'f')">
<xsl:element name="span">
<xsl:attribute name="style">
<xsl:text>display:none</xsl:text>
</xsl:attribute>
<xsl:attribute name="id">
<xsl:value-of select="substring($xmlid, 3, 4)" />
</xsl:attribute>
<xsl:apply-templates select="node()" />
</xsl:element>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
我的问题是我需要为每个 900 个字符创建一个新的 <div class="book-content">
。但我不想削减我的 s
元素,所以我需要计算我必须在一个 <div class="book-content">
中包含多少 s
元素才能拥有大约 900 个字符。
这是一个有趣的问题,但您的示例涉及太多其他问题。我更喜欢用我自己的例子单独解决这个问题。
考虑以下输入:
XML
<book>
<chapter id="A">
<para>
<sentence id="1" length="23">Mary had a little lamb,</sentence>
<sentence id="2" length="29">His fleece was white as snow,</sentence>
<sentence id="3" length="30">And everywhere that Mary went,</sentence>
</para>
<para>
<sentence id="4" length="24">The lamb was sure to go.</sentence>
<sentence id="5" length="34">He followed her to school one day,</sentence>
</para>
<para>
<sentence id="6" length="27">Which was against the rule,</sentence>
<sentence id="7" length="35">It made the children laugh and play</sentence>
<sentence id="8" length="24">To see a lamb at school.</sentence>
</para>
<para>
<sentence id="9" length="34">And so the teacher turned it out, </sentence>
<sentence id="10" length="27">But still it lingered near.</sentence>
</para>
</chapter>
<chapter id="B">
<para>
<sentence id="11" length="35">Summertime, and the livin' is easy.</sentence>
<sentence id="12" length="40">Fish are jumpin' and the cotton is high.</sentence>
<sentence id="13" length="52">Oh, Your daddy's rich and your mamma's good lookin'.</sentence>
<sentence id="14" length="35">So hush little baby, don't you cry.</sentence>
<sentence id="15" length="54">One of these mornings you're going to rise up singing.</sentence>
</para>
<para>
<sentence id="16" length="57">Then you'll spread your wings and you'll take to the sky.</sentence>
<sentence id="17" length="35">So hush little baby, don't you cry.</sentence>
</para>
</chapter>
</book>
注意:length
值仅供参考;我们不会在解决方案中使用它们。
我们的任务是将总长度超过 200 个字符的每个章节拆分为多个章节,方法是仅移动 整个 个句子,同时保留句子组之间的原始段落边界。
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
xmlns:set="http://exslt.org/sets"
extension-element-prefixes="exsl set">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="chapter">
<xsl:call-template name="split-chapter">
<xsl:with-param name="nodes" select="para/sentence"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="split-chapter">
<xsl:param name="nodes"/>
<xsl:param name="limit" select="200"/>
<xsl:param name="remaining-nodes" select="dummy-node"/>
<!-- 1. Calculate the total length of nodes -->
<xsl:variable name="lengths">
<xsl:for-each select="$nodes">
<length>
<xsl:value-of select="string-length()" />
</length>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="total-length" select="sum(exsl:node-set($lengths)/length)" />
<!-- 2. Process the chapter: -->
<xsl:choose>
<!-- If chapter is too long and can be shortened ... -->
<xsl:when test="$total-length > $limit and count($nodes) > 1">
<!-- ... try again with one node less. -->
<xsl:call-template name="split-chapter">
<xsl:with-param name="nodes" select="$nodes[not(position()=last())]"/>
<xsl:with-param name="remaining-nodes" select="$remaining-nodes | $nodes[last()]"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<!-- Otherwise create a chapter with the current nodes ... -->
<chapter id="{@id}" length="{$total-length}" >
<!-- ... list the paras participating in this chapter ... -->
<xsl:for-each select="$nodes/parent::para">
<para>
<!-- ... and process the nodes still left in each para. -->
<xsl:apply-templates select="set:intersection(sentence, $nodes)"/>
</para>
</xsl:for-each>
</chapter>
<!-- Then process any remaining nodes. -->
<xsl:if test="$remaining-nodes">
<xsl:call-template name="split-chapter">
<xsl:with-param name="nodes" select="$remaining-nodes"/>
</xsl:call-template>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
结果
<?xml version="1.0" encoding="utf-8"?>
<book>
<chapter id="A" length="167">
<para>
<sentence id="1" length="23">Mary had a little lamb,</sentence>
<sentence id="2" length="29">His fleece was white as snow,</sentence>
<sentence id="3" length="30">And everywhere that Mary went,</sentence>
</para>
<para>
<sentence id="4" length="24">The lamb was sure to go.</sentence>
<sentence id="5" length="34">He followed her to school one day,</sentence>
</para>
<para>
<sentence id="6" length="27">Which was against the rule,</sentence>
</para>
</chapter>
<chapter id="A" length="120">
<para>
<sentence id="7" length="35">It made the children laugh and play</sentence>
<sentence id="8" length="24">To see a lamb at school.</sentence>
</para>
<para>
<sentence id="9" length="34">And so the teacher turned it out, </sentence>
<sentence id="10" length="27">But still it lingered near.</sentence>
</para>
</chapter>
<chapter id="B" length="162">
<para>
<sentence id="11" length="35">Summertime, and the livin' is easy.</sentence>
<sentence id="12" length="40">Fish are jumpin' and the cotton is high.</sentence>
<sentence id="13" length="52">Oh, Your daddy's rich and your mamma's good lookin'.</sentence>
<sentence id="14" length="35">So hush little baby, don't you cry.</sentence>
</para>
</chapter>
<chapter id="B" length="146">
<para>
<sentence id="15" length="54">One of these mornings you're going to rise up singing.</sentence>
</para>
<para>
<sentence id="16" length="57">Then you'll spread your wings and you'll take to the sky.</sentence>
<sentence id="17" length="35">So hush little baby, don't you cry.</sentence>
</para>
</chapter>
</book>
我有一个使用 TEI 构建的 XML 文件:
<div type="chapter" n="1">
<p>
<s xml:id="e_1">sentence e1.</s>
<s xml:id="f_1">sentence f1</s>
</p>
<p>
<s xml:id="e_2"> sentence e2</s>
<s xml:id="f_2"> sentence f2</s>
</p>
</div>
<div type="chapter" n="2">
<!-- -->
</div>
我需要将它转换成这个HTML结构:
<div>
<h1>Chapter 1</h1>
<div class="book-content">
<p>
<span class='source-language-sent' data-source-id='1'>sentence e1.</span>
<span id='1' style='display:none'>sentence f1</span>
</p>
<p>
<span class='source-language-sent' data-source-id='2'>sentence e2</span>
<span id='2' style='display:none'>sentence f2</span>
</p>
</div>
</div>
<div>
<h1>Chapter 2</h1>
<div class="book-content">
<!-- -->
</div>
</div>
现在我使用这个 XSLT 文件:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tei="http://www.tei-c.org/ns/1.0" version="1.0">
<xsl:output method="html" encoding="UTF-8" indent="yes" />
<xsl:template match="tei:body">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="tei:teiHeader">
<xsl:comment>
<xsl:apply-templates select="node()" />
</xsl:comment>
</xsl:template>
<!--create chapter-->
<xsl:template match="tei:div">
<xsl:element name="div">
<xsl:element name="div">
<xsl:attribute name="class">
<xsl:text>book-content</xsl:text>
</xsl:attribute>
<xsl:element name="h1">
<xsl:text>Chapter</xsl:text>
<xsl:value-of select="@n" />
</xsl:element>
<xsl:apply-templates select="node()" />
</xsl:element>
</xsl:element>
</xsl:template>
<!-- create p-->
<xsl:template match="tei:p">
<xsl:element name="p">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
<!-- create s-->
<xsl:template match="tei:s">
<xsl:variable name="xmlid" select="@xml:id" />
<xsl:if test="starts-with($xmlid, 'e')">
<xsl:element name="span">
<xsl:attribute name="class">
<xsl:text>source-language-sent</xsl:text>
</xsl:attribute>
<xsl:attribute name="data-source-id">
<xsl:value-of select="substring($xmlid, 3, 4)" />
</xsl:attribute>
<xsl:apply-templates select="node()" />
</xsl:element>
</xsl:if>
<xsl:if test="starts-with($xmlid, 'f')">
<xsl:element name="span">
<xsl:attribute name="style">
<xsl:text>display:none</xsl:text>
</xsl:attribute>
<xsl:attribute name="id">
<xsl:value-of select="substring($xmlid, 3, 4)" />
</xsl:attribute>
<xsl:apply-templates select="node()" />
</xsl:element>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
我的问题是我需要为每个 900 个字符创建一个新的 <div class="book-content">
。但我不想削减我的 s
元素,所以我需要计算我必须在一个 <div class="book-content">
中包含多少 s
元素才能拥有大约 900 个字符。
这是一个有趣的问题,但您的示例涉及太多其他问题。我更喜欢用我自己的例子单独解决这个问题。
考虑以下输入:
XML
<book>
<chapter id="A">
<para>
<sentence id="1" length="23">Mary had a little lamb,</sentence>
<sentence id="2" length="29">His fleece was white as snow,</sentence>
<sentence id="3" length="30">And everywhere that Mary went,</sentence>
</para>
<para>
<sentence id="4" length="24">The lamb was sure to go.</sentence>
<sentence id="5" length="34">He followed her to school one day,</sentence>
</para>
<para>
<sentence id="6" length="27">Which was against the rule,</sentence>
<sentence id="7" length="35">It made the children laugh and play</sentence>
<sentence id="8" length="24">To see a lamb at school.</sentence>
</para>
<para>
<sentence id="9" length="34">And so the teacher turned it out, </sentence>
<sentence id="10" length="27">But still it lingered near.</sentence>
</para>
</chapter>
<chapter id="B">
<para>
<sentence id="11" length="35">Summertime, and the livin' is easy.</sentence>
<sentence id="12" length="40">Fish are jumpin' and the cotton is high.</sentence>
<sentence id="13" length="52">Oh, Your daddy's rich and your mamma's good lookin'.</sentence>
<sentence id="14" length="35">So hush little baby, don't you cry.</sentence>
<sentence id="15" length="54">One of these mornings you're going to rise up singing.</sentence>
</para>
<para>
<sentence id="16" length="57">Then you'll spread your wings and you'll take to the sky.</sentence>
<sentence id="17" length="35">So hush little baby, don't you cry.</sentence>
</para>
</chapter>
</book>
注意:length
值仅供参考;我们不会在解决方案中使用它们。
我们的任务是将总长度超过 200 个字符的每个章节拆分为多个章节,方法是仅移动 整个 个句子,同时保留句子组之间的原始段落边界。
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
xmlns:set="http://exslt.org/sets"
extension-element-prefixes="exsl set">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="chapter">
<xsl:call-template name="split-chapter">
<xsl:with-param name="nodes" select="para/sentence"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="split-chapter">
<xsl:param name="nodes"/>
<xsl:param name="limit" select="200"/>
<xsl:param name="remaining-nodes" select="dummy-node"/>
<!-- 1. Calculate the total length of nodes -->
<xsl:variable name="lengths">
<xsl:for-each select="$nodes">
<length>
<xsl:value-of select="string-length()" />
</length>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="total-length" select="sum(exsl:node-set($lengths)/length)" />
<!-- 2. Process the chapter: -->
<xsl:choose>
<!-- If chapter is too long and can be shortened ... -->
<xsl:when test="$total-length > $limit and count($nodes) > 1">
<!-- ... try again with one node less. -->
<xsl:call-template name="split-chapter">
<xsl:with-param name="nodes" select="$nodes[not(position()=last())]"/>
<xsl:with-param name="remaining-nodes" select="$remaining-nodes | $nodes[last()]"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<!-- Otherwise create a chapter with the current nodes ... -->
<chapter id="{@id}" length="{$total-length}" >
<!-- ... list the paras participating in this chapter ... -->
<xsl:for-each select="$nodes/parent::para">
<para>
<!-- ... and process the nodes still left in each para. -->
<xsl:apply-templates select="set:intersection(sentence, $nodes)"/>
</para>
</xsl:for-each>
</chapter>
<!-- Then process any remaining nodes. -->
<xsl:if test="$remaining-nodes">
<xsl:call-template name="split-chapter">
<xsl:with-param name="nodes" select="$remaining-nodes"/>
</xsl:call-template>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
结果
<?xml version="1.0" encoding="utf-8"?>
<book>
<chapter id="A" length="167">
<para>
<sentence id="1" length="23">Mary had a little lamb,</sentence>
<sentence id="2" length="29">His fleece was white as snow,</sentence>
<sentence id="3" length="30">And everywhere that Mary went,</sentence>
</para>
<para>
<sentence id="4" length="24">The lamb was sure to go.</sentence>
<sentence id="5" length="34">He followed her to school one day,</sentence>
</para>
<para>
<sentence id="6" length="27">Which was against the rule,</sentence>
</para>
</chapter>
<chapter id="A" length="120">
<para>
<sentence id="7" length="35">It made the children laugh and play</sentence>
<sentence id="8" length="24">To see a lamb at school.</sentence>
</para>
<para>
<sentence id="9" length="34">And so the teacher turned it out, </sentence>
<sentence id="10" length="27">But still it lingered near.</sentence>
</para>
</chapter>
<chapter id="B" length="162">
<para>
<sentence id="11" length="35">Summertime, and the livin' is easy.</sentence>
<sentence id="12" length="40">Fish are jumpin' and the cotton is high.</sentence>
<sentence id="13" length="52">Oh, Your daddy's rich and your mamma's good lookin'.</sentence>
<sentence id="14" length="35">So hush little baby, don't you cry.</sentence>
</para>
</chapter>
<chapter id="B" length="146">
<para>
<sentence id="15" length="54">One of these mornings you're going to rise up singing.</sentence>
</para>
<para>
<sentence id="16" length="57">Then you'll spread your wings and you'll take to the sky.</sentence>
<sentence id="17" length="35">So hush little baby, don't you cry.</sentence>
</para>
</chapter>
</book>