2

I have a code such as below:

<abc>
<aaa>123</aaa>
</abc>
<abc>
<aaa>123</aaa>
</abc>

When I give the XPath expression as:

//*[name() = 'aaa']

I get the output as

{'123','123'}

What I want is to get only one result from the XPath expression so that I can compare it with a property that I give as expected result.

kjhughes
  • 106,133
  • 27
  • 181
  • 240

2 Answers2

2

First of all, you can simply use //aaa, to select all aaa elements. If you only want the first selected element then use (//aaa)[1].

Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
  • I dont want the element. I want the value in the element. – Irine Mathew Dec 23 '15 at 21:08
  • Which XPath version and which host language do you use? – Martin Honnen Dec 23 '15 at 21:14
  • @IrineMathew - Try adding `text()` to the path: `(//aaa)[1]/text()` – Daniel Haley Dec 23 '15 at 21:23
  • 1
    @DanielHaley, if its XPath 1.0 then doing `string(//aaa)` or `number(//aaa)` seems more appropriate if a primitive value is needed as the result. With XPath 2.0 I would use `(//aaa/data(.))[1]`. – Martin Honnen Dec 23 '15 at 21:25
  • @IrineMathew, your original expression `//*[name() = 'aaa']` selects element nodes as well, so if that worked, I don't see why my suggestion selecting the first element should not do. If you want a primitive value like a string or a number then see my suggestion in the comment to Daniel. – Martin Honnen Dec 23 '15 at 21:27
  • @DanielHaley - Your solution worked. Thank you so much. – Irine Mathew Dec 23 '15 at 21:41
  • @IrineMathew - It's really Martin's solution so please accept his answer. He also has very good points in his comment to me, so be sure to read it. – Daniel Haley Dec 23 '15 at 21:45
0

You may want to have a look at this answer:

https://stackoverflow.com/a/4747858/36305

It demonstrates a way, using XSLT, to build an XPath expression for selecting every node of a given XML document and even generating an XPath expression for comparing the values:


<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:variable name="vApos">'</xsl:variable>

    <xsl:template match="*[@* or not(*)] ">
      <xsl:if test="not(*)">
         <xsl:apply-templates select="ancestor-or-self::*" mode="path"/>
         <xsl:value-of select="concat('=',$vApos,.,$vApos)"/>
         <xsl:text>&#xA;</xsl:text>
        </xsl:if>
        <xsl:apply-templates select="@*|*"/>
    </xsl:template>

    <xsl:template match="*" mode="path">
        <xsl:value-of select="concat('/',name())"/>
        <xsl:variable name="vnumPrecSiblings" select=
         "count(preceding-sibling::*[name()=name(current())])"/>
        <xsl:if test="$vnumPrecSiblings">
            <xsl:value-of select="concat('[', $vnumPrecSiblings +1, ']')"/>
        </xsl:if>
    </xsl:template>

    <xsl:template match="@*">
        <xsl:apply-templates select="../ancestor-or-self::*" mode="path"/>
        <xsl:value-of select="concat('[@',name(), '=',$vApos,.,$vApos,']')"/>
        <xsl:text>&#xA;</xsl:text>
    </xsl:template>
</xsl:stylesheet>

When applied on the provided input (wrapped in a top-element to become well-formed):

<t>
    <abc>
        <aaa>123</aaa>
    </abc>
    <abc>
        <aaa>123</aaa>
    </abc>
</t>

the result is a set of XPath expressions selecting each of the elements that have a single text child, and comparing the string value of the element and the child:

/t/abc/aaa='123'
/t/abc[2]/aaa='123'

This also generates expressions, that involve comparisons of attribute values, and whose Boolean value is true() exactly when the attribute value comparison is true.

For example, if the provided XML document was this:

<t>
    <abc x="1" y="2">
        <aaa>123</aaa>
    </abc>
    <abc z="3">
        <aaa>123</aaa>
    </abc>
</t>

then the result of the transformation is:

/t/abc[@x='1']
/t/abc[@y='2']
/t/abc/aaa='123'
/t/abc[2][@z='3']
/t/abc[2]/aaa='123'
Community
  • 1
  • 1
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431