Как захватить атрибуты от предыдущих братьев и сестер в XSLT

Я пытаюсь преобразовать ужасный XML с встроенным форматированием richtext в HTML. Я нашел способ идентифицировать начало маркированного списка на основе атрибута в предыдущем узле, но я не могу понять, как закончить маркированный список. Проблема в том, что атрибуты каждого блока текста определяются либо в предыдущем узле, либо в первом абзаце серии.

У меня есть следующий XML:

<?xml version="1.0" encoding="UTF-8"?>
<document>
    <item>
        <richtext>
            <pardef/>
            <par def='20'><run>This is the first </run><run>paragraph of the preamble.</run></par>
            <par><run>This is the second paragraph of the </run><run>preamble.</run></par>
            <pardef list='bullet'/>
            <par def='21'><run>This is the </run><run>first bullet.</run></par>
            <par><run>This is the second </run><run>bullet.</run></par>
            <par def='20'><run>This is the first </run><run>paragraph of the conclusion.</run></par>
            <par><run>This is the second paragraph of the </run><run>conclusion.</run></par>
        </richtext>
    </item>
</document>

Я хочу получить следующий результат:

<p>This is the first paragraph of the preamble.</p>
<p>This is the second paragraph of the preamble.</p>
<ul>
    <li>This is the first bullet.</li>
    <li>This is the second bullet.</li>
</ul>
<p>This is the first paragraph of the conclusion.</p>
<p>This is the second paragraph of the conclusion.</p>

У меня есть следующий XSLT:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

    <xsl:key name="key-for-par" match="document/item/richtext/par" use="generate-id(preceding-sibling::pardef[1])"/>
    <xsl:output indent="yes"/>

    <xsl:template match="/">
        <xsl:apply-templates select="document/item/richtext/pardef" />
    </xsl:template>

    <xsl:template match="pardef[@list = 'bullet']">
        <ul>
            <xsl:for-each select="key('key-for-par', generate-id(.))">
                <li>
                    <xsl:value-of select="run" separator=""/>
                </li>
            </xsl:for-each>
        </ul>
    </xsl:template>

    <xsl:template match="pardef[not(@list)]">
            <xsl:for-each select="key('key-for-par', generate-id(.))">
                <p>
                    <xsl:value-of select="run" separator=""/>
                </p>
            </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>

xml,xslt,

0

Ответов: 1


0 принят

Согласно комментариям, считая, что def = 21 - это начало списка маркеров, мы можем игнорировать «pardef» и использовать «par» в select const, мы можем определить, когда писать ul, li, p и соответствующие теги закрытия. Я попробовал это на образце и даже по некоторым его вариантам и отлично работал:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output indent="yes"/>

    <xsl:template match="/">
        <xsl:apply-templates select="document/item/richtext/par" />
    </xsl:template>

    <xsl:template match="par">
    <xsl:if test="@def and preceding-sibling::par[@def][1][@def='21']"><xsl:text disable-output-escaping="yes">&lt;/ul&gt;</xsl:text></xsl:if>

    <xsl:choose>

        <xsl:when test="@def=21 or (not(@def) and preceding-sibling::par[@def][1][@def='21'])">
            <xsl:if test="@def=21"><xsl:text disable-output-escaping="yes">&lt;ul&gt;</xsl:text></xsl:if>
            <li>
                <xsl:for-each select="run">
                    <xsl:value-of select="text()" separator=""/>
                </xsl:for-each>
            </li>   
        </xsl:when>

        <xsl:when test="not(@def=21)">
            <p>
                <xsl:for-each select="run">
                    <xsl:value-of select="text()" separator=""/>
                </xsl:for-each>
            </p>    
        </xsl:when>     

    </xsl:choose>   

    </xsl:template>
</xsl:stylesheet>
XML, XSLT,
Похожие вопросы