在XSLT 2.0中输出一系列兄弟姐妹

时间:2017-06-15 01:49:33

标签: xml xslt

我有一个转换为HTML的ODT文档。该文档具有描述各种字段的特定文本字段。我用它来创建电子邮件。现在我想将它们转换为PHP文档。

字段如下所示:

<p><b>Day #0</b></p>
<p><b>Subject:</b></p>
<p>Here is a subject for Day #0</p>
<p><b>Body</b></p>
<p>A Paragraph One</p>
<p>A Paragraph Two</p>
<p>A Paragraph Three</p>
<p><b>Day #1</b></p>
<p><b>Subject:</b></p>
<p>Here is a subject for Day #1</p>
<p><b>Body</b></p>
<p>B Paragraph One</p>
<p>B Paragraph Two</p>
<p>B Paragraph Three</p>
<p>B Paragraph Four</p>
<p>B Paragraph Five</p>
<p><b>Day #3</b></p>
<p><b>Subject:</b></p>
[...etc...]

在XSTL中,我能够正确提取日期编号和主题。但是,我真的不知道如何提取所有Body段落。

正如我们在上面的示例中所看到的,在某些情况下可能有三个,在其他情况下可能有五个段落......它可以是从一个到无穷大的任何东西(零不是可接受的情况,如果有帮助的话。)

<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@* | node()">
   <xsl:apply-templates select="/html/body/p[starts-with(b, 'Day #')]"/>
</xsl:template>

<!-- Extracting Day #, easy -->
<xsl:template match="*[starts-with(., 'Day #')]">
    <xsl:value-of select="substring-after(b, 'Day #')"/><xsl:text disable-output-escaping="yes"> =&gt; array(
</xsl:text>

<!-- Extracting Subject, easy -->
<xsl:text disable-output-escaping="yes">    "subject" =&gt; "</xsl:text>
<xsl:copy-of select="following-sibling::p[2]/node()"/>
<xsl:text disable-output-escaping="yes">",
    "message" =&gt;
&lt;&lt;&lt;EOF</xsl:text>
<!-- Extracting Body, how can I copy all the siblings up to the next Day #? -->
<xsl:copy-of select="following-sibling::p[4], following-sibling::p[5]"/>
<!-- I tried with this but it did not help...
      following-sibling::p[4] &gt;&gt; following-sibling::p[4]/b[starts-with(., 'Day #')]"/
-->
<xsl:text>
EOF
    ),
</xsl:text>
</xsl:template>

</xsl:stylesheet>

预期的输出有一个标题和页脚没有在这里显示,但最后是一个带有子数组数组的PHP脚本。这里的示例展示了我期望在这里展示的XSLT代码:

0 => array(
    "subject" => "Here is a subject for Day #0",
    "message" =>
<<<EOF
<p>A Paragraph One</p>
<p>A Paragraph Two</p>
<p>A Paragraph Three</p>
EOF
),

1 => array(
    "subject" => "Here is a subject for Day #1",
    "message" =>
<<<EOF
<p>B Paragraph One</p>
<p>B Paragraph Two</p>
<p>B Paragraph Three</p>
<p>B Paragraph Four</p>
<p>B Paragraph Five</p>
EOF
),
...etc...

请注意,我可以在条目列表的末尾添加逗号(,)。 PHP允许这样的。但是,最后一个条目后面不会跟"Day #123",虽然如果处理这种特殊情况太复杂,很容易在源中再添加一行。

请注意,正文中的段落也可能使用其他标记,例如锚点(<a>),粗体(<b>)和斜体(<i>)。

P.S。我在Ubuntu 16.04上使用Saxon版本9.1.0.8J

1 个答案:

答案 0 :(得分:2)

正如我在您的问题的评论中提到的,这是一个分组问题。我相信以下样式表产生的输出非常接近预期的输出:

XSLT 2.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8" />

<xsl:template match="/html">
    <xsl:for-each-group select="body/p" group-starting-with="p[starts-with(b, 'Day #')]">
        <xsl:value-of select="substring-after(b, 'Day #')"/>
        <xsl:text> => array(&#10;"subject" => "</xsl:text>
        <xsl:value-of select="current-group()[3]"/>
        <xsl:text>",&#10;"message" =>&#10;&lt;&lt;&lt;EOF&#10;</xsl:text>
        <xsl:for-each select="current-group()[position() > 4]">
            <xsl:text>&lt;p></xsl:text>
            <xsl:value-of select="."/>
            <xsl:text>&lt;/p>&#10;</xsl:text>
        </xsl:for-each>     
        <xsl:text>EOF&#10;),&#10;&#10;</xsl:text>
    </xsl:for-each-group>
</xsl:template>

</xsl:stylesheet>

演示:http://xsltransform.net/93dEHFS/1