Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 9038127
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 16, 20262026-06-16T09:24:51+00:00 2026-06-16T09:24:51+00:00

Given an element as context I want to select the preceding sibling element and

  • 0

Given an element as context I want to select the preceding sibling element and check to see if it has a particular name. The caveat is that I do not want to select it if there is an intervening text node that has non-whitespace content.

For example, given this XML document…

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

…then:

  • For “a1” there should be no match (there is no <a> sibling element immediately preceding it)
  • For “a2” then “a1” should be matched (there is no intervening text node)
  • For “a3” there should be no match (there is an intervening text node with non-whitespace contents)
  • For “a4” then “a3” should be matched (the intervening text node is only whitespace)
  • For “a5” there should be no match (the preceding sibling element is not an <a>).

I can check to see if the preceding sibling is an <a> with preceding-sibling::*[1][name()="a"]

However, I can’t figure out how to say “select the following sibling node, regardless of element or textness, and see if that’s not text or normalize-space(.)="". My best guess was this:

preceding-sibling::*[1][name()="a"][following-sibling::node()[1][not(text()) or normalize-space(.)=""]]

…but that appears to have no effect.


Here’s my test Ruby file:

require 'nokogiri'

xpath = 'preceding-sibling::*[1][name()="a"][following-sibling::node()[1][not(text()) or normalize-space(.)=""]]'
fragment = Nokogiri::XML.fragment '<a>a1</a><a>a2</a> b <a>a3</a> <a>a4</a> <b/> <a>a5</a>'    

fragment.css('a').each{ |a| p [a.text,a.xpath(xpath).to_s] }
#=> ["a1", ""]
#=> ["a2", ""]
#=> ["a3", "<a>a2</a>"]
#=> ["a4", "<a>a3</a>"]
#=> ["a5", ""]

The result for “a2” and “a3” are what is wrong and confuses me. It finds the preceding <a> correctly, but then does not correctly verify that the first following-sibling of that is either not text (which should allow “a2” to find “a1”) or that it is whitespace only (which should prevent “a3” from finding “a2”.


Edit: Here’s the XPath I was writing, and what I intended it to do:

  • preceding-sibling::*[1][name()="a"]… – find the first preceding element, and ensure that it is an <a>. This appears to be working as desired.

    • [following-sibling::node()[1][…]] – ensure that the first following node (of the found preceding <a>) matches some conditions

      • not(text()) or normalize-space(.)="" – ensure that this following node is either not a text node, or that the normalized space of it is empty
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-16T09:24:53+00:00Added an answer on June 16, 2026 at 9:24 am

    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>
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have some XML that has an extra element and I want it gone.
I want to be able to match against all elements in a given context
See title. Additionally, how can I tell if a given child element is only
Given the xml: <element>text</element> ... <element>text</element> And xsl: <xsl:for-each select=element> ... </xsl:for-each> What do
i want to transform some xml into HTML that has the following format: <TR><TD>
In cases where a given SOAP header element has a given value (for example,
I have an NodeSeq object and want to select a given node which is
how can i get immediate parent of a given element ? $(e.target).parent() ?
How do I get a tuple/list element given a condition in python? This occurs
This portion of code checks if a number given (First element in a list)

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.