A tricky XSLT transformation - xslt

I have a loosely structured XHTML data and I need to convert it to better structured XML.
Here's the example:
<tbody>
<tr>
<td class="header"><img src="http://www.abc.com/images/icon_apples.gif"/><img src="http://www.abc.com/images/flag/portugal.gif" alt="Portugal"/> First Grade</td>
</tr>
<tr>
<td>Green</td>
<td>Round shaped</td>
<td>Tasty</td>
</tr>
<tr>
<td>Red</td>
<td>Round shaped</td>
<td>Bitter</td>
</tr>
<tr>
<td>Pink</td>
<td>Round shaped</td>
<td>Tasty</td>
</tr>
<tr>
<td class="header"><img src="http://www.abc.com/images/icon_strawberries.gif"/><img src="http://www.abc.com/images/flag/usa.gif" alt="USA"/> Fifth Grade</td>
</tr>
<tr>
<td>Red</td>
<td>Heart shaped</td>
<td>Super tasty</td>
</tr>
<tr>
<td class="header"><img src="http://www.abc.com/images/icon_bananas.gif"/><img src="http://www.abc.com/images/flag/congo.gif" alt="Congo"/> Third Grade</td>
</tr>
<tr>
<td>Yellow</td>
<td>Smile shaped</td>
<td>Fairly tasty</td>
</tr>
<tr>
<td>Brown</td>
<td>Smile shaped</td>
<td>Too sweet</td>
</tr>
I am trying to achieve following structure:
<data>
<entry>
<type>Apples</type>
<country>Portugal</country>
<rank>First Grade</rank>
<color>Green</color>
<shape>Round shaped</shape>
<taste>Tasty</taste>
</entry>
<entry>
<type>Apples</type>
<country>Portugal</country>
<rank>First Grade</rank>
<color>Red</color>
<shape>Round shaped</shape>
<taste>Bitter</taste>
</entry>
<entry>
<type>Apples</type>
<country>Portugal</country>
<rank>First Grade</rank>
<color>Pink</color>
<shape>Round shaped</shape>
<taste>Tasty</taste>
</entry>
<entry>
<type>Strawberries</type>
<country>USA</country>
<rank>Fifth Grade</rank>
<color>Red</color>
<shape>Heart shaped</shape>
<taste>Super</taste>
</entry>
<entry>
<type>Bananas</type>
<country>Congo</country>
<rank>Third Grade</rank>
<color>Yellow</color>
<shape>Smile shaped</shape>
<taste>Fairly tasty</taste>
</entry>
<entry>
<type>Bananas</type>
<country>Congo</country>
<rank>Third Grade</rank>
<color>Brown</color>
<shape>Smile shaped</shape>
<taste>Too sweet</taste>
</entry>
</data>
Firstly I need to extract the fruit type from the tbody/tr/td/img[1]/#src, secondly the country from tbody/tr/td/img[2]/#alt attribute and finally the grade from tbody/tr/td itself.
Next I need to populate all the entries under each category while including those values (like shown above).
But... As you can see, the the data I was given is very loosely structured. A category is simply a td and after that come all the items in that category. To make the things worse, in my datasets, the number of items under each category varies between 1 and 100...
I've tried a few approaches but just can't seem to get it. Any help is greatly appreciated. I know that XSLT 2.0 introduces xsl:for-each-group, but I am limited to XSLT 1.0.

In this case, you are not actually grouping elements. It is more like ungrouping them.
One way to do this is to use an xsl:key to look up the "header" row for each of detail rows.
<xsl:key name="fruity"
match="tr[not(td[#class='header'])]"
use="generate-id(preceding-sibling::tr[td[#class='header']][1])"/>
i.e For each detail row, get the most previous header row.
Next, you can then match all your header rows like so:
<xsl:apply-templates select="tr/td[#class='header']"/>
Within the matching template, you could then extract the type, country and rank. Then to get the associated detail rows, it is a simple case of looking at the key for the parent row:
<xsl:apply-templates select="key('fruity', generate-id(..))">
Here is the overall XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="fruity"
match="tr[not(td[#class='header'])]"
use="generate-id(preceding-sibling::tr[td[#class='header']][1])"/>
<xsl:template match="/tbody">
<data>
<!-- Match header rows -->
<xsl:apply-templates select="tr/td[#class='header']"/>
</data>
</xsl:template>
<xsl:template match="td">
<!-- Match associated detail rows -->
<xsl:apply-templates select="key('fruity', generate-id(..))">
<!-- Extract relevant parameters from the td cell -->
<xsl:with-param name="type" select="substring-before(substring-after(img[1]/#src, 'images/icon_'), '.gif')"/>
<xsl:with-param name="country" select="img[2]/#alt"/>
<xsl:with-param name="rank" select="normalize-space(text())"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="tr">
<xsl:param name="type"/>
<xsl:param name="country"/>
<xsl:param name="rank"/>
<entry>
<type>
<xsl:value-of select="$type"/>
</type>
<country>
<xsl:value-of select="$country"/>
</country>
<rank>
<xsl:value-of select="$rank"/>
</rank>
<color>
<xsl:value-of select="td[1]"/>
</color>
<shape>
<xsl:value-of select="td[2]"/>
</shape>
<taste>
<xsl:value-of select="td[3]"/>
</taste>
</entry>
</xsl:template>
</xsl:stylesheet>
When applied to your input document, the following output is generated:
<data>
<entry>
<type>apples</type>
<country>Portugal</country>
<rank>First Grade</rank>
<color>Green</color>
<shape>Round shaped</shape>
<taste>Tasty</taste>
</entry>
<entry>
<type>apples</type>
<country>Portugal</country>
<rank>First Grade</rank>
<color>Red</color>
<shape>Round shaped</shape>
<taste>Bitter</taste>
</entry>
<entry>
<type>apples</type>
<country>Portugal</country>
<rank>First Grade</rank>
<color>Pink</color>
<shape>Round shaped</shape>
<taste>Tasty</taste>
</entry>
<entry>
<type>strawberries</type>
<country>USA</country>
<rank>Fifth Grade</rank>
<color>Red</color>
<shape>Heart shaped</shape>
<taste>Super tasty</taste>
</entry>
<entry>
<type>bananas</type>
<country>Congo</country>
<rank>Third Grade</rank>
<color>Yellow</color>
<shape>Smile shaped</shape>
<taste>Fairly tasty</taste>
</entry>
<entry>
<type>bananas</type>
<country>Congo</country>
<rank>Third Grade</rank>
<color>Brown</color>
<shape>Smile shaped</shape>
<taste>Too sweet</taste>
</entry>
</data>

Related

Find the maximum entries using xslt

I have a table and I want to find the maximum entries from tbody and thead. I have mentioned the table code below.
<table>
<thead>
<row>
<entry>
<p>aaa</p>
<p>aaa</p>
</entry>
</row>
<row>
<entry>
<p>bbb</p>
<p>bbb</p>
</entry>
<entry>
<p>ccc</p>
<p>ccc</p>
</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<p>ddd</p>
<p>ddd</p>
</entry>
</row>
<row>
<entry>
<p>eee</p>
<p>eee</p>
</entry>
<entry>
<p>fff</p>
<p>fff</p>
</entry>
<entry>
<p>ggg</p>
<p>ggg</p>
</entry>
<entry>
<p>hhh</p>
<p>hhh</p>
</entry>
<entry>
<p>iii</p>
<p>iii</p>
</entry>
</row>
<row>
<entry>
<p>jjj</p>
<p>jjj</p>
</entry>
<entry>
<p>kkk</p>
<p>kkk</p>
</entry>
</row>
</tbody>
</table>
It means here maximum entry count is 5 and it is xpath is table/tbody/row[2]/entry. I want to find the maxmium entry value between thead and tbody.
I have used xslt code for this. But it is not work properly. It always returns me 0 as the answer.
<xsl:template match="table">
<xsl:variable name="is-notempty-table" select="max(count(thead/row/entry))" />
<xsl:value-of select="$is-notempty-table" />
</xsl:template>
Help me to solve this.
The problem with doing this...
<xsl:variable name="is-notempty-table" select="max(count(thead/row/entry))" />
Is that count(thead/row/entry) is only going to return a single value; namely the count of all entry nodes in the thead. (And it will return 3, not 0). If you want to find the maximum count of entry nodes for the rows within thead, the expression you want is this
<xsl:variable name="is-notempty-table" select="max(thead/row/count(entry))" />
Or, for tbody
<xsl:variable name="is-notempty-table" select="max(tbody/row/count(entry))" />
Or, to check the entire table...
<xsl:variable name="is-notempty-table" select="max(*/row/count(entry))" />
As an aside, the use of the variable name is-notempty-table suggests you are just wanting to check if the table has entry nodes in? If so, you can just do this...
<xsl:variable name="is-notempty-table" select="*/row/entry" />
<xsl:if test="$is-notempty-table">Table is not empty</xsl:if>
Inside <xsl:template match="table"> it seems you want to compute max(*/row/count(entry)) (if there are no other children for the table element) or perhaps max((thead|tbody)/row/count(entry)) if you expect other elements like a tfoot.
Both expressions assume XSLT/XPath 2 or later.

Compare a processing instruction and get the file name

I'm writing an XSLT in which I need to see if a value is in preprocessing instruction. In my XML, the preprocessing looks like below.
<?xpp MAIN;1;1;0;0;69;0;0?>
Sample XML
<root>
<?xpp MAIN;1;0;0;0;73;0;0?>
<preface role="guideline">
<title>title</title>
<section role="group">
<para>data</para>
</section>
<section role="group">
<title>
<?xpp lp;0.5p?>Licences</title>
<itemizedlist mark="bullet">
<listitem>
<para>itemdata</para>
</listitem>
</itemizedlist>
</section>
<section role="group">
<title>
<?xpp lp;0.5p?>Letters to the Editor</title>
<itemizedlist mark="bullet">
<listitem>
<para><?xpp MAIN;1;0;0;0;74;0;0?>item data</para>
</listitem>
</itemizedlist>
</section>
</preface>
</root>
Sample1 XML
<root>
<?xpp MAIN;1;0;0;0;83;0;0?>
<preface role="guideline">
<title>title</title>
<section role="group">
<para>data</para>
</section>
<section role="group">
<title>
<?xpp lp;0.5p?>Licences</title>
<itemizedlist mark="bullet">
<listitem>
<para>itemdata</para>
</listitem>
</itemizedlist>
</section>
<section role="group">
<title>
<?xpp lp;0.5p?>Letters to the Editor</title>
<itemizedlist mark="bullet">
<listitem>
<para><?xpp MAIN;1;0;0;0;84;0;0?>item data</para>
</listitem>
</itemizedlist>
</section>
</preface>
</root>
For the below XML, I need to do the task of going through files and checking for the data. The Above sample XML and Sample1 XML are the files that I've loop through.
<root>
<table frame="none" tabstyle="wrap4">
<tgroup cols="4">
<colspec colnum="1" colname="col1" colwidth="10*"/>
<colspec colnum="2" colname="COLSPEC0" colwidth="10.00*"/>
<colspec colnum="3" colname="col2" colwidth="275*"/>
<colspec colnum="4" colname="col3" colwidth="15*"/>
<tbody>
<row>
<entry colsep="0" rowsep="0">Text1</entry>
<entry colsep="0" rowsep="0"/>
<entry colsep="0" rowsep="0"/>
<entry colsep="0" rowsep="0" align="right">75</entry>
</row>
<row>
<entry colsep="0" rowsep="0">Text2</entry>
<entry colsep="0" rowsep="0"/>
<entry colsep="0" rowsep="0"/>
<entry colsep="0" rowsep="0" align="right">84</entry>
</row>
</tbody>
</tgroup>
</table>
</root>
Here first I'm trying to loop through all the files available, in each file, look for the preprocessing containing MAIN in it and then see if my value is present in that preprocessing instruction. Below is my XSLT block.
<xsl:template match="entry[#align='right']" mode="y">
<xsl:analyze-string select="." regex="([0-9]+)">
<xsl:matching-substring>
<xsl:variable name="prent" select="document(document('file:///C:\Users\userId\Desktop\Proview\AUS Journal\02FEB/title.xml')/entry/file/#name)/*[contains(//root/processing-instruction('xpp')[contains(.,'MAIN')],regex-group(1))]/substring-before(tokenize(document-uri(/), '/')[last()], '.')"/>
<xsl:variable name="cha">
<xsl:value-of select="$prent"/>
</xsl:variable>
<xsl:variable name="size">
<xsl:value-of select="string-length($cha)"/>
</xsl:variable>
<xsl:variable name="conct">
<xsl:value-of select="concat($cha,'/pg_',.)"/>
</xsl:variable>
<a href="{$conct}">
<xsl:value-of select="regex-group(1)"/>
</a>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
When I run this I get the below error.
XSLT 2.0 Debugging Error: Error: file:///C:/Users/userId/Desktop/Proview/AUS%20Journal/02FEB/XSLT/Journal.xsl:674: Wrong occurrence to match required sequence type - Details: - XPTY0004: The supplied sequence ('2' item(s)) has the wrong occurrence to match the sequence type xs:string ('zero or one').
please let me know how can I fix this and get job done.
Thanks
Try whether changing the step
*[contains(//root/processing-instruction('xpp')[contains(.,'MAIN')],regex-group(1))]
to
*[//root/processing-instruction('xpp')[contains(.,'MAIN')][contains(., regex-group(1))]]
fixes the problem.

Confused in XSLT scripting

hi i want to create an HTML table that shows the numbers(Years) in one column and the data in the second column. below is my xslt. i'm really confused as they have the same tags.
<chapter>
<row>
<entry>
<para>1984</para>
</entry>
<entry>
<para>International Business Companies Act passed into
law.</para>
</entry>
</row>
<row>
<entry>
<para>2004</para>
</entry>
<entry>
<para>BVI Business Companies Act passed into law, coming into
force on 1 January 2005.</para>
</entry>
</row>
<row>
<entry>
<para>2005</para>
</entry>
<entry>
<para>All three corporate statutes exist in parallel and it is
possible to incorporate companies under any of them.</para>
</entry>
</row>
<row>
<entry>
<para>2006</para>
</entry>
<entry>
<para>Incorporation provisions in the International Business
Companies Act and the Companies Act are repealed on 31 December
2005; the Acts remain in force but new companies may only be
incorporated under the BVI Business Companies Act.</para>
</entry>
</row>
</chapter>
Thanks
I am assuming that the first two elements of the XML that you posted are wrapped by a <row> element and all the rows are grouped under a parent element called rows.
If some of those assumptions are wrong, tell me and I will correct the code.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output mode="html" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="text()" />
<!-- I am assuming that the parent element for the set of row elements is
named rows. You can change this to match your XML -->
<xsl:template match="chapter">
<table>
<tr>
<th>Year</th>
<th>Data</th>
</tr>
<xsl:apply-templates select="row" />
</table>
</xsl:template>
<xsl:template match="row">
<tr>
<xsl:apply-templates select="*" />
</tr>
</xsl:template>
<xsl:template match="para">
<td><xsl:value-of select="." /></td>
</xsl:template>
</xsl:stylesheet>
UPDATE : If you just want to match the first entry/para element for each row, then you should use a template like the following one:
<xsl:template match="entry[1]/para">
<!-- Put your code here -->
</xsl:template>
Here's an example of creating a HTML table using XSLT. The dataset used in the example is very similar to your XML, just substitute the examples <book> tags with your <row> tags and so on.

How to access the element in this input using XPATH

I am using XPath to reach to a text value as shown in the input xml.
<stream>
<Services>
<ServicesSub>
<title>Parameter Calculations</title>
<list1 type="unordered-bullet">
<item>
<premier>
<link Id="1222">Sheet Size</link>
<link Id="433">Hydraulic System</link>
</premier>
</item>
<item>
<premier> Review
<link Id="342332">Diagnose</link>
Rational Approach</premier>
</item>
<item>
<premier>
<link Id="222">Process</link>
</premier>
</item>
</list1>
</ServicesSub>
<ServicesSub>
<title>Parameter Set</title>
<table TableNumber="tab1" titlesource="no-title" frame="all" pgwide="page-wide">
<tgroup cols="5" colsep="1" rowsep="1" align="left" charoff="50" char="">
<colspec ColumnName="col1" colwidth="2.77in"/>
<colspec ColumnName="col2" colwidth="1.10in"/>
<thead valign="bottom">
<row RowNumber="row1">
<entry ColumnName="col1" morerows="0" rotate="0" valign="bottom" align="center">
<ptxt>Price less</ptxt>
</entry>
<entry ColumnName="col2" morerows="0" rotate="0" valign="bottom" align="center">
<ptxt>Price more</ptxt>
</entry>
<entry ColumnName="col3" morerows="0" rotate="0" valign="bottom" align="center">
<ptxt>Open Price</ptxt>
</entry>
</row>
</thead>
<tbody valign="top">
<row RowNumber="row1">
<entry ColumnName="col1" morerows="0" rotate="0" valign="middle">
<ptxt>Sheet</ptxt>
</entry>
<entry ColumnName="col2" morerows="0" rotate="0" valign="middle" align="center">
<ptxt>Sheets1</ptxt>
</entry>
</row>
<row RowNumber="row2">
<entry ColumnName="col1" morerows="0" rotate="0" valign="middle">
<ptxt>Electric failure</ptxt>
</entry>
<entry ColumnName="col2" morerows="0" rotate="0" valign="middle" align="center">
<ptxt>Elec fails</ptxt>
</entry>
</row>
</tbody>
</tgroup>
</table>
</ServicesSub>
</Services>
</stream>
I am intersted only in the values "price less", "price more", "Open Price" under 'Parameter Set' title and under thead --> row --> entry.
I just started learning the xpath and xslt.. please help me in fetchin these values..
output expected:
<Value = "Price less"\>
<Value = "Price more"\>
<Value = "Open Price"\>
I tried until this...
/stream/Services/ServicesSub/title[text() = "Parameter Set" ]/following::*
Thanks
Ramm
Try this XPath which should return all matching ptxt elements.
stream/Services/ServicesSub
[title[text() = 'Parameter Set']]/table/tgroup/thead/row/entry/ptxt
For example, given the following XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="stream/Services/ServicesSub[title[text() = 'Parameter Set']]/table/tgroup/thead/row/entry/ptxt"/>
</xsl:template>
<xsl:template match="ptxt">
<value>
<xsl:value-of select="." />
</value>
</xsl:template>
</xsl:stylesheet>
When applied to your input XML produces the following output
<value>Price less</value>
<value>Price more</value>
<value>Open Price</value>
Note that you haven't mentioned about whether you have duplicate values, and how these should be handled. You need to read up on grouping (Muenchian Grouping in XSLT 1.0) if you have duplicates and want them ignored.

XSLT Transformation value of select - Blank output?

Please advise, noob to XSLT transformation.
What am I missing from the following XSLvalue-of? I have the following XML data. Then in my transformation listed below I am referencing these elements but I get empty fields in my output. I must be using the incorrect syntax on the <xsl:value-of select="./userInfo/addressMap/entry[2]/firstName"/>
<userInfo>
<addressMap>
<entry>
<key>2</key>
<value>
<addressField1>21941 Main Drive</addressField1>
<addressField2>Apt XYZ</addressField2>
<addressType>0</addressType>
<city>Lake Forest</city>
<emailId>krystal#bogus.com</emailId>
<firstName>Krystal M</firstName>
<lastName>Obama</lastName>
<phoneNo>9495551212</phoneNo>
<state>CA</state>
<zipCode>92630</zipCode>
</value>
</entry>
</addressMap>
</userInfo>
<table border="0" width="600" cellpadding="5" cellspacing="5">
<tr bgcolor="#cccccc" style="font-size:14px; font-weight:bold;">
<td align="left">SHIPPING INFO</td>
<td align="left">BILLING INFO</td>
</tr>
<tr bgcolor="#ffffff" style="font-size:12px;">
<td align="left"><table border="0">
<tr>
<td><xsl:value-of select="./userInfo/addressMap/entry[2]/firstName"/> 
<xsl:value-of select="./userInfo/addressMap/entry[2]/lastName"/></td>
</tr>
<tr>
<td><xsl:value-of select="./userInfo/addressMap/entry[2]/addressField1"/></td>
</tr>
<xsl:choose>
<xsl:when test="./userInfo/addressMap/entry[2]/addressField2 and ./userInfo/addressMap/entry[2]/addressField2 != ''">
<tr>
<td><xsl:value-of select="./userInfo/addressMap/entry[2]/addressField2"/></td>
</tr>
</xsl:when>
<xsl:otherwise>
<tr>
<td> </td>
</tr>
</xsl:otherwise>
</xsl:choose>
<tr>
<td><xsl:value-of select="./userInfo/addressMap/entry[2]/city"/>, 
<xsl:value-of select="./userInfo/addressMap/entry[2]/state"/> 
<xsl:value-of select="./userInfo/addressMap/entry[2]/zipCode"/> USA </td>
</tr>
<tr>
<td><xsl:value-of select="./userInfo/addressMap/entry[2]/phoneNo"/></td>
</tr>
</table>
Here is my entire xml data.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<cart>
<basketQuantity>0</basketQuantity>
<cartTotals>
<amtDueToBePaid>35.4</amtDueToBePaid>
<discountList>Employee Discount</discountList>
<giftWrapping>0.0</giftWrapping>
<preferredMemberAmountCharged>0.0</preferredMemberAmountCharged>
<preferredMemberSavings>0.0</preferredMemberSavings>
<promoCodeSavings>0.0</promoCodeSavings>
<promoShipping>0.0</promoShipping>
<regularMerchandise>59.0</regularMerchandise>
<regularShipping>0.0</regularShipping>
<saleMerchandise>59.0</saleMerchandise>
<savings>23.6</savings>
<shippingSavings>0.0</shippingSavings>
<subTotal>35.4</subTotal>
<tax>0.0</tax>
<taxableMerchandise>35.4</taxableMerchandise>
<total>35.4</total>
</cartTotals>
<errorAndWarnings/>
<itemsList>
<discountMap>
<entry>
<key>Employee Discount</key>
<value>23.6</value>
</entry>
</discountMap>
<itemName>Rosette Smocked Top</itemName>
<productId>45711923</productId>
<promoPrice>0.0</promoPrice>
<quantity>1</quantity>
<regularPrice>59.0</regularPrice>
<returnValue>35.4</returnValue>
<salePrice>59.0</salePrice>
<savings>23.6</savings>
<taxCode>0.0</taxCode>
<unitTax>0.0</unitTax>
<upc>457119500004</upc>
<uuid>b18ffa87c0a86f6f14618000479d92c9</uuid>
</itemsList>
<orderPlaced>false</orderPlaced>
<pipelineSessionId>abcxyz</pipelineSessionId>
<shipping>
<availableShippingMap>
<entry>
<key>2</key>
<value>
<actualShippingCost>7.95</actualShippingCost>
<deliveryDays>0</deliveryDays>
<savings>0.0</savings>
<shippingDiscount>0.0</shippingDiscount>
<shippingMethodName>2nd Day</shippingMethodName>
</value>
</entry>
<entry>
<key>1</key>
<value>
<actualShippingCost>0.0</actualShippingCost>
<deliveryDays>0</deliveryDays>
<savings>0.0</savings>
<shippingDiscount>0.0</shippingDiscount>
<shippingMethodName>Standard Shipping</shippingMethodName>
</value>
</entry>
<entry>
<key>3</key>
<value>
<actualShippingCost>19.95</actualShippingCost>
<deliveryDays>0</deliveryDays>
<savings>0.0</savings>
<shippingDiscount>0.0</shippingDiscount>
<shippingMethodName>Overnight Delivery</shippingMethodName>
</value>
</entry>
</availableShippingMap>
<savings>0.0</savings>
<selectedShippingMethodId>1</selectedShippingMethodId>
<shippingCost>0.0</shippingCost>
<shippingPromo>0.0</shippingPromo>
</shipping>
<userInfo>
<addressMap>
<entry>
<key>2</key>
<value>
<addressField1>21941 Main Drive</addressField1>
<addressField2>Apt XYZ</addressField2>
<addressType>0</addressType>
<city>Lake Forest</city>
<emailId>krystal#bogus.com</emailId>
<firstName>Krystal M</firstName>
<lastName>Obama</lastName>
<phoneNo>9495551212</phoneNo>
<state>CA</state>
<zipCode>92630</zipCode>
</value>
</entry>
</addressMap>
</userInfo>
</cart>
The problem is the "entry[2]", it's not selecting the entry with key 2 as you intend it to.
Off the top of my head, that should be something like "./userInfo/addressMap/entry[string(key) = 2]/value/firstName".