XSLT Закрыть узлы в xml, если обнаружен дочерний узел - PullRequest
0 голосов
/ 06 ноября 2019

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

<?xml version="1.0" encoding="UTF-8"?>
<parent>
    <para>
        <emphasis>
            <emphasis>
                blah 0 
                <Xref ref="1"/>
                blah 1
            </emphasis>
        </emphasis>
    </para>
    <para>
        blah 2 <Xref ref="2"/> blah 3
    </para>
</parent>

Я бы хотел получить Xref узлы вне узлов para, независимо от их глубины.

Используя следующий XSLT 1.0 код:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />

    <xsl:template match="@*|node()" priority="0">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:key name="kPrecedingXref" match="node()[not(self::Xref)]" use="generate-id(following-sibling::Xref[1])"/>

    <xsl:template match="para[Xref]" priority="1">
        <xsl:apply-templates select="Xref"/>
        <xsl:if test="count(Xref/following-sibling::node())&gt;0">
            <para>
                <xsl:apply-templates select="Xref/following-sibling::node()[not(self::Xref) and not(following-sibling::Xref)]"/>
            </para>
        </xsl:if>
    </xsl:template>

    <xsl:template match="Xref" priority="1">
        <xsl:if test="parent::para">
            <para>
                <xsl:apply-templates select="key('kPrecedingXref', generate-id())"/>
            </para>
        </xsl:if>

        <toolRef><xsl:value-of select="@ref"/></toolRef>
    </xsl:template>

    <xsl:template match="emphasis[Xref]" priority="1">
        <xsl:copy>
                <xsl:apply-templates select="node()[following-sibling::Xref]" />
        </xsl:copy>
        <xsl:apply-templates select="Xref"/>
        <xsl:copy>
                <xsl:apply-templates select="node()[preceding-sibling::Xref]" />
        </xsl:copy>
    </xsl:template>

</xsl:transform>

, который обрабатывает это, но может получить только узлы Xref вне своего прямого родительского узла. Как я могу изменить этот код, чтобы получить это:

Требуемый вывод

<parent>
   <para>
      <emphasis>
         <emphasis>
            blah 0 
         </emphasis>
      </emphasis>
   </para>
   <toolRef>1</toolRef>
   <para>
      <emphasis>
         <emphasis>
            blah 1
         </emphasis>
      </emphasis>
   </para>
   <para>blah 2 </para>
   <toolRef>2</toolRef>
   <para> blah 3</para>
</parent>

Вот полный пример кода: http://xsltransform.net/nbiCsZM/4

1 Ответ

0 голосов
/ 07 ноября 2019

Благодаря michael.hor257k и большому беспокойству я наконец-то нашел решение своей проблемы.

Вот мой рабочий код XSLT 1.0

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

    <xsl:template match="@*|node()" priority="0">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="@*|node()" priority="0" mode="EXTRACT_XREF">
        <xsl:param name="i" select="0"/>
        <xsl:if test="descendant-or-self::text()[count(preceding-sibling::Xref)=$i]">
            <xsl:copy>
                <xsl:apply-templates select="@*"/>
                <xsl:apply-templates select="node()" mode="EXTRACT_XREF">
                    <xsl:with-param name="i" select="$i"/>
                </xsl:apply-templates>
            </xsl:copy>
        </xsl:if>
    </xsl:template>

    <xsl:template match="para[descendant::Xref]" priority="1">
        <xsl:call-template name="recursive">
            <xsl:with-param name="node" select="."/>
            <xsl:with-param name="count" select="0"/>
            <xsl:with-param name="limit" select="count(descendant::Xref)"/>
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="recursive">
        <xsl:param name="node"/>
        <xsl:param name="count" select="0"/>
        <xsl:param name="limit"/>
        <xsl:if test="$count&lt;=$limit">
            <xsl:apply-templates select="$node" mode="EXTRACT_XREF">
                <xsl:with-param name="i" select="$count"/>
            </xsl:apply-templates>
            <xsl:apply-templates select="$node/descendant::Xref[$count + 1]"/>
            <xsl:call-template name="recursive">
                <xsl:with-param name="node" select="$node"/>
                <xsl:with-param name="count" select="$count + 1"/>
                <xsl:with-param name="limit" select="$limit"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

    <xsl:template match="Xref" priority="1">
        <toolRef>
            <xsl:attribute name="ref">
                <xsl:value-of select="@ref"/>
            </xsl:attribute>
        </toolRef>
    </xsl:template>

</xsl:transform>

Я также добавил несколько узлов тестирования, которые должны быть скопированы без изменений, чтобы проверить все возможные случаи:

Входной XML

<?xml version="1.0" encoding="UTF-8"?>
<parent>
    <dontChangeThisNode></dontChangeThisNode>
    <para>
        <emphasis mode="bold">
            <emphasis mode="underline">blah 0<Xref ref="1"/>blah 1<Xref ref="3"/> blah</emphasis>
        </emphasis>
    </para>
    <dontChangeThisNodeEither>hop</dontChangeThisNodeEither>
    <para>blah 2 <Xref ref="2"/> blah 3</para>
    <para>blah 4</para>
</parent>

И, наконец, вот чтоэтот код преобразует его в:

вывод XML

<?xml version="1.0" encoding="UTF-8"?>
<parent>
   <dontChangeThisNode/>
   <para>
      <emphasis mode="bold">
         <emphasis mode="underline">blah 0</emphasis>
      </emphasis>
   </para>
   <toolRef ref="1"/>
   <para>
      <emphasis mode="bold">
         <emphasis mode="underline">blah 1</emphasis>
      </emphasis>
   </para>
   <toolRef ref="3"/>
   <para>
      <emphasis mode="bold">
         <emphasis mode="underline"> blah</emphasis>
      </emphasis>
   </para>
   <dontChangeThisNodeEither>hop</dontChangeThisNodeEither>
   <para>blah 2 </para>
   <toolRef ref="2"/>
   <para> blah 3</para>
   <para>blah 4</para>
</parent>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...