开发者

How to map PCDATA between two empty tags into one tag?

开发者 https://www.devze.com 2023-01-08 08:43 出处:网络
I have this following doubt in xslt coding. my input is : <text><p>some text</p> <p/>some text <emph>....</emph>.........<p/> </text>

I have this following doubt in xslt coding.

my input is : <text><p>some text</p> <p/>some text <emph>....</emph>.........<p/> </text>

And the output that i need is

<text><p>some text</p><p>some text <emph>....</emph>.........</p></text>

How am i supposed to map the values present 开发者_运维知识库between two empty "p" tags in to a non-empty "p" tag?


This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes"/>
    <xsl:template match="@*|node()" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()[1]"/>
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::node()[1]"/>
    </xsl:template>
    <xsl:template match="p[not(node())][last()][count(../p[not(node())]) mod 2]" priority="1">
        <xsl:call-template name="identity"/>
    </xsl:template>
    <xsl:template match="p[not(node())][not(position() mod 2)]" priority="1"/>
    <xsl:template match="p[not(node())]">
            <p>
                <xsl:apply-templates select="following-sibling::node()[1]"/>
            </p>
            <xsl:apply-templates select="following-sibling::p[not(node())][1]/following-sibling::node()[1]"/>
    </xsl:template>
</xsl:stylesheet>

With inputs:

1 - (p with content and two empty p)

<text><p>some text</p> <p/>some text <emph>....</emph>.........<p/> </text>

2 - (Four empty p)

<text><p/>some text<p/> <p/>some text <emph>....</emph>.........<p/> </text>

3 - (Three empty p)

<text><p/>some text <p/>some text <emph>....</emph>.........<p/> </text>

4 - (p with content and three empty p)

<text><p/>some text <p/>some text <p><emph>....</emph></p>.........<p/> </text>

5 - (p with content two empty p siblings and other level two empty p)

<text><p>some text</p> <p/>some text <emph><p/>....<p/></emph>.........<p/> </text>

Results:

1 -

<text><p>some text</p><p>some text <emph>....</emph>.........</p></text>

2 -

<text><p>some text</p><p>some text <emph>....</emph>.........</p></text>

3 -

<text><p>some text </p>some text <emph>....</emph>.........<p></p></text>

4 -

<text><p>some text </p>some text <p><emph>....</emph></p>.........<p></p></text>

5 -

<text><p>some text</p><p>some text <emph><p>....</p></emph>.........</p></text>

Note: Breaking the recursion and following node by node in "serial" way.

EDIT: I think that now it covers every case. Take notice that you can't define with your format when you had odds p wich of the two (preceding or following) want to enclosed. So, this is "associative" left to rigth.

EDIT 2: Better use of last() (How did I miss that?)

EDIT 3: Better pattern matching allow to compact code.


This transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kfollowingNodes"
 match="node()[not(self::p[not(node())])]"
 use="generate-id(preceding-sibling::p[not(node())][1])"/>

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

 <xsl:template match=
 "p[not(node()) and following-sibling::p[not(node())]]">
  <xsl:variable name="vFollowing"
       select="key('kfollowingNodes', generate-id())"/>
  <xsl:if test="$vFollowing">
      <p>
       <xsl:apply-templates mode="wrap" select=
       "key('kfollowingNodes', generate-id())"/>
      </p>
  </xsl:if>
 </xsl:template>

 <xsl:template match=
 "p[not(node()) and not(following-sibling::p[not(node())])]"/>

 <xsl:template match="node()[not(self::p[not(node())])][preceding-sibling::p[not(node())]]"/>

 <xsl:template match="node()" mode="wrap">
  <xsl:call-template name="identity"/>
 </xsl:template>
</xsl:stylesheet>

when applied on this XML document:

<text>
    <p>some text</p>
    <p/>some other text
    <emph>Hello World</emph>
    yet another text
    <p/>
</text>

produces the desired output:

<text>
    <p>some text</p>
    <p>some other text
    <emph>Hello World</emph>
    yet another text
    </p>
</text>
0

精彩评论

暂无评论...
验证码 换一张
取 消