我需要使用XSLT重新排列元素标记

时间:2017-02-10 11:58:58

标签: xml xslt xslt-2.0

我有多个主题,我需要包含section标签以及带有编号ID的主题元素

我的输入XML是:

<Article>
<Title>Mam</Title>
<Items>
    <Item>
        <Name>cyst1?</Name>
        <Body>
            <h1>aaa</h1><p>knee1.</p>
            <h2>bbb</h2><p>knee2.</p>
        </Body>
    </Item>
    <Item>
        <Name>cyst2?</Name>
        <Body>
            <p>knee3.</p>
        </Body>
    </Item>
</Items>

XSL我用作:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="#all">
<xsl:template match="Article">
    <xsl:apply-templates/>
</xsl:template>
<xsl:template match="Title"/>
<xsl:template match="h1"/>
<xsl:template match="h2"/>
<xsl:template match="Items">
    <xsl:for-each-group select="*" group-starting-with="Items">
        <topic>
            <xsl:attribute name="id">topic_Head<xsl:number count="Items | Item"/>
            </xsl:attribute>
            <title>
                <xsl:value-of select="//Title"/>
            </title>
            <xsl:for-each-group select="current-group()" group-starting-with="Item">
                <xsl:choose>
                    <xsl:when test="self::Item">
                        <topic>
                            <xsl:attribute name="id">topic_<xsl:number count="Items | Item"/>
                            </xsl:attribute>
                            <xsl:apply-templates select="node()"/>
                        </topic>
                    </xsl:when>
                    <xsl:otherwise>
                        <body>
                            <xsl:apply-templates select="current-group()"/>
                        </body>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each-group>
        </topic>
    </xsl:for-each-group>
</xsl:template>
<xsl:template match="Body">
    <body>
        <xsl:apply-templates/>
    </body>
</xsl:template>
<xsl:template match="p">
    <p>
        <xsl:apply-templates/>
    </p>
</xsl:template>
<xsl:template match="Name">
    <title>
        <xsl:apply-templates/>
    </title>
</xsl:template>

输出我得到了:

<topic id="topic_1">
<title>Mam</title>
<topic id="topic_2">
    <title>cyst1?</title>
    <body>
        <p>knee1.</p><p>knee2.</p>
    </body>
</topic>
<topic id="topic_3">
    <title>cyst2?</title>
    <body>
        <p>knee3.</p>
    </body>
</topic>

预期产出:

<topic id="topic_1">
<title>Mam</title>
<topic id="topic_2">
    <title>cyst1?</title>
    <body>
        <section id="section1">
            <title>aaa</title><p>knee1.</p>
            <section id="section2">
                <title>bbb</title><p>knee2.</p>
            </section>
        </section>
    </body>
</topic>
<topic id="topic_3">
    <title>cyst2?</title>
    <body>
        <p>knee3.</p>
    </body>
</topic>

我需要h1和h2作为具有Id属性的部分,并按照标题顺序关闭。

请建议我对此进行编码。提前谢谢。

1 个答案:

答案 0 :(得分:0)

以下styleshhet会起作用。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:ahf="http://www.antennahouse.com/names/XSLT/Functions/Document"
    exclude-result-prefixes="#all">

    <xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="Article">
        <topic>
            <xsl:attribute name="id" select="ahf:genTopicId(.)"/>
            <xsl:apply-templates/>
        </topic>
    </xsl:template>

    <xsl:template match="Title">
        <title>
            <xsl:apply-templates/>
        </title>
    </xsl:template>

    <xsl:template match="Items">
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="Item">
        <topic>
            <xsl:attribute name="id" select="ahf:genTopicId(.)"/>
            <xsl:apply-templates/>            
        </topic>
    </xsl:template>

    <xsl:template match="Name">
        <title>
            <xsl:apply-templates/>
        </title>
    </xsl:template>

    <xsl:template match="Body">
        <body>
            <xsl:call-template name="groupBody">
                <xsl:with-param name="prmBodyElem" select="*"/>
            </xsl:call-template>
        </body>
    </xsl:template>

    <xsl:template name="groupBody">
        <xsl:param name="prmBodyElem" as="element()*"/>
        <xsl:variable name="maxHn" as="xs:integer" select="ahf:getMaxHn($prmBodyElem)"/>
        <xsl:choose>
            <xsl:when test="$maxHn eq $notHn">
                <xsl:apply-templates select="$prmBodyElem"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:for-each-group select="$prmBodyElem" group-adjacent="ahf:genGroupNo(.,$maxHn,$prmBodyElem)">
                    <xsl:choose>
                        <xsl:when test="current-grouping-key() eq 0">
                            <xsl:apply-templates select="current-group()"/>
                        </xsl:when>
                        <xsl:otherwise>
                            <section>
                                <xsl:attribute name="id" select="ahf:genSectionId(current-group()[1])"/>
                                <title>
                                    <xsl:apply-templates select="./node()"/>
                                </title>
                                <xsl:call-template name="groupBody">
                                    <xsl:with-param name="prmBodyElem" select="subsequence(current-group(),2)"/>
                                </xsl:call-template>
                            </section>
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:for-each-group>            
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:variable name="notHn" as="xs:integer" select="9999"/>

    <xsl:function name="ahf:getMaxHn" as="xs:integer">
        <xsl:param name="prmElem" as="element()+"/>
        <xsl:variable name="hn" as="xs:integer*">
            <xsl:for-each select="$prmElem">
                <xsl:choose>
                    <xsl:when test="matches(name(),'h[1-9]')">
                        <xsl:sequence select="xs:integer(substring(name(),2))"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:sequence select="$notHn"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each>
        </xsl:variable>
        <xsl:sequence select="min($hn)"/>
    </xsl:function>

    <xsl:template match="p">
        <p>
            <xsl:apply-templates/>
        </p>
    </xsl:template>

    <!-- Generate id number for topic -->
    <xsl:function name="ahf:genTopicId" as="xs:string">
        <xsl:param name="prmElem" as="element()"/>
        <xsl:sequence select="concat('topic_',count($prmElem|root($prmElem)//*[self::Article or self::Item][. &lt;&lt; $prmElem]))"/>
    </xsl:function>

    <!-- Grouping by hN (N = $prmMaxHn)
         0: not h1, h2, h3... 
         > 1: hN group
      -->
    <xsl:function name="ahf:genGroupNo" as="xs:integer">
        <xsl:param name="prmElem" as="element()"/>
        <xsl:param name="prmMaxHn" as="xs:integer"/>
        <xsl:param name="prmRange" as="element()*"/>
        <xsl:variable name="GroupHn" as="xs:string" select="concat('h',$prmMaxHn)"/>
        <xsl:sequence select="count($prmElem[self::*[name() eq $GroupHn]]) + count($prmElem/preceding-sibling::*[name() eq $GroupHn][(. is $prmRange[1]) or (. &gt;&gt; $prmRange[1])])"/>
    </xsl:function>

    <!--Generate id number for section -->
    <xsl:function name="ahf:genSectionId" as="xs:string">
        <xsl:param name="prmElem" as="element()"/>
        <xsl:sequence select="concat('section_',count($prmElem|$prmElem/preceding::*[matches(name(),'h[1-9]')]))"/>
    </xsl:function>

</xsl:stylesheet>

[结果]

<?xml version="1.0" encoding="UTF-8"?>
<topic id="topic_1">
   <title>Mam</title>
   <topic id="topic_2">
      <title>cyst1?</title>
      <body>
         <section id="section_1">
            <title>aaa</title>
            <p>knee1.</p>
            <section id="section_2">
               <title>bbb</title>
               <p>knee2.</p>
            </section>
         </section>
      </body>
   </topic>
   <topic id="topic_3">
      <title>cyst2?</title>
      <body>
         <p>knee3.</p>
      </body>
   </topic>
</topic>

我仍然担心如果预期结果是DITA主题实例,则不允许嵌套节元素。