1

A subset of my XML data looks like this.

<results>
  <result>
    <finishedSqFt>2608</finishedSqFt>
    <bedrooms>3</bedrooms>
    <totalRooms>9</totalRooms>
    <lastSoldDate>05/25/2001</lastSoldDate>
  </result>
</results>

My goal is to use a single Xpath expression to extract an array of the string-values of the following elements:

[ finishedSqFt, bedrooms, bathrooms, lastSoldDate, ]

Notice the bathrooms variable is not included in my data.

The Xpath expression I am using is as follows:

(//results/result/finishedSqFt)[1] | (//results/result/bedrooms)[1] |
(//results/result/bathrooms)[1] | (//results/result/lastSoldDate)[1]

The result I get is:

[ 2608, 3, "05/25/2001", ]

The result I want is:

[ 2608, 3, "default", "05/25/2001", ]

How do I accomplish this? How do I insert a default value when the xPath does not return a match?

What am I doing wrong?

Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
Let Me Tink About It
  • 15,156
  • 21
  • 98
  • 207

1 Answers1

3

Use this XPath 2.0 expression:

'[',
 string-join((/*/*/finishedSqFt/string(), 
              /*/*/bedrooms/string(), 
              (/*/*/bathrooms/string(), 'default')[1], 
              /*/*/lastSoldDate/string()), ', '),
 ']'

XSLT 2.0 - based verification

This transformation:

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

  <xsl:template match="/">
    <xsl:sequence select=
    "'[',
     string-join((/*/*/finishedSqFt/string(), 
                  /*/*/bedrooms/string(), 
                  (/*/*/bathrooms/string(), 'default')[1], 
                  /*/*/lastSoldDate/string()), ', '),
     ']'
    "/>
  </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document:

<results>
  <result>
    <finishedSqFt>2608</finishedSqFt>
    <bedrooms>3</bedrooms>
    <totalRooms>9</totalRooms>
    <lastSoldDate>05/25/2001</lastSoldDate>
  </result>
</results>

evaluates the above XPath expression and outputs the result of this evaluation -- the wanted, correct result:

[ 2608, 3, default, 05/25/2001 ]

II. XPath 1.0 solution

concat('[ ',
        string(/*/*/finishedSqFt), ', ',
        string(/*/*/bedrooms), ', ',
        substring(string(/*/*/bathrooms), 1 div boolean(string(/*/*/bathrooms)) ),
        substring('default', 1 div not(string(/*/*/bathrooms)) ),    
        ', ',
        string(/*/*/lastSoldDate), 
        ' ]'
        )

XSLT 1.0 - 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:value-of select=
    "concat('[ ',
            string(/*/*/finishedSqFt), ', ',
            string(/*/*/bedrooms), ', ',
            substring(string(/*/*/bathrooms), 1 div boolean(string(/*/*/bathrooms)) ),
            substring('default', 1 div not(string(/*/*/bathrooms)) ),    
            ', ',
            string(/*/*/lastSoldDate), 
            ' ]'
            )
    "/>
  </xsl:template>
</xsl:stylesheet>

when applied on the sameprovided XML document, the same correct result is produced:

[ 2608, 3, default, 05/25/2001 ]

For explanation of the XPath 1.0 solution see this answer

Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431