Hi all, I'm a bit of an XPath noob and I'd be much obliged if you'd point me in the right direction here.

I want to select the first <product> in the source that has the child node <name> = 'bread'

The expression below yields the correct naswer but I'm thinking there must be a better/more concise way of doing it:

/TOWN/SHOP/BASKET[PRODUCT/NAME='bread'][1]/PRODUCT[NAME='bread'][1]

<TOWN>
	<SHOP>
		<BASKET type="plastic">
			<PRODUCT>
				<NAME>bread</NAME>
				<VAL>BROWN</VAL>
			</PRODUCT>				
			<PRODUCT>
				<NAME>bread</NAME>
				<VAL>WHITE</VAL>				
			</PRODUCT>			
		</BASKET>
		
		<BASKET type="metal">
			<PRODUCT>
				<NAME>pasta</NAME>
				<VAL>MAC</VAL>
			</PRODUCT>
			<PRODUCT>
				<NAME>bread</NAME>
				<VAL>TOASTED</VAL>
			</PRODUCT>			
		</BASKET>					
	</SHOP>
</TOWN>

Cheers

Recommended Answers

All 3 Replies

There's a couple ways to do that, but your path isn't as bad as you might think :) You've just got a bit of redundancy that you don't need.

This is an explicit way from the root.
/TOWN/SHOP/BASKET/PRODUCT[1][NAME = 'bread']

You can also go directly to the first PRODUCT node anywhere in the document.
//PRODUCT[1][NAME = 'bread']

Your XPath works in this instance. However, I need to be able to find the first bread product in the document where we cannot assume that it will be in the first position in a basket (or even that it exists in every basket); i.e. it also needs to work for this piece of xml

<?xml version="1.0" encoding="UTF-8"?>
<TOWN>
<SHOP>
	<BASKET type="black">
		<PRODUCT>
			<NAME>beans</NAME>
			<VAL>BAKED</VAL>
		</PRODUCT>
	</BASKET>
	<BASKET type="green">
		<PRODUCT>
			<NAME>rice</NAME>
			<VAL>BROWN</VAL>
		</PRODUCT>	
		<PRODUCT>
			<NAME>bread</NAME>
			<VAL>BROWN</VAL>
		</PRODUCT>
		<PRODUCT>
			<NAME>bread</NAME>
			<VAL>WHITE</VAL>
		</PRODUCT>
	</BASKET>
	<BASKET type="blue">
		<PRODUCT>
			<NAME>pasta</NAME>
			<VAL>MAC</VAL>
		</PRODUCT>
		<PRODUCT>
			<NAME>bread</NAME>
			<VAL>TOASTED</VAL>
		</PRODUCT>
	</BASKET>
</SHOP>
</TOWN>

This XPath will work but I don't think it's as efficient as the first solution:

/TOWN/SHOP/descendant::PRODUCT[NAME='bread'][1]

Any way we can improve our XPath?

Nope! That's pretty efficient and it gets exactly what you want. FYI, that is a really simple short and efficient XPath. There's little room for improvement :) You should see some that I write.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.