3
4

1 回答 1

5

Use:

/*/a/preceding-sibling::node()
       [not(self::text()[not(normalize-space())])]
            [1]
              [self::a]

XSLT - based verification:

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

 <xsl:template match="/">
     <xsl:copy-of select=
       "/*/a
          /preceding-sibling::node()
                      [not(self::text()[not(normalize-space())])]
                                        [1]
                                         [self::a]
    "/>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document:

<r>
  <a>a1</a><a>a2</a>
   b
  <a>a3</a>
    <a>a4</a>
  <b/>
  <a>a5</a>
</r>

the XPath expression is evaluated and the nodes that are selected by this evaluation, are copied to the output:

<a>a1</a>
<a>a3</a>

Update:

What is wrong with the XPath expression in the question?

The problem is here:

[not(text()) or normalize-space(.)='']

This tests if the context node doesn't have a text node child.

But the OP wants to test if the context node is a text node.

Solution:

Replace the above with:

[not(self::text()) or normalize-space(.)='']

XSLT - based verification:

<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:template match="/*/a">
     <xsl:copy-of select=
     "preceding-sibling::*[1]
                      [name()='a']
                         [following-sibling::node()[1]
                                    [not(self::text()) or normalize-space(.)='']
                       ]"/>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

Now this transformation produces exactly the wanted result:

<a>a1</a>
<a>a3</a>
于 2012-12-26T20:07:13.677 回答