Reputation: 119856
We utilise a third party web service that returns XML which looks something like (cut down for brevity):
<Response>
<block name="availability">
<block name="cqual">
<a name="result-code" format="text">L</a>
</block>
<block name="exchange">
<a name="code" format="text">MRDEN</a>
</block>
<block name="mqual">
<a name="rate-adaptive" format="text">G</a>
</block>
</block>
<block name="products">
<block>
<a name="product-id" format="counting">1235</a>
<block name="realms">
<block>
<a name="realm" format="text">-u@surfuk1</a>
</block>
</block>
</block>
<block>
<a name="product-id" format="counting">1236</a>
<block name="realms">
<block>
<a name="realm" format="text">-u@surfuk2</a>
</block>
</block>
</block>
<block>
<a name="product-id" format="counting">1237</a>
<block name="realms">
<block>
<a name="realm" format="text">-u@surfuk3</a>
</block>
</block>
</block>
</block>
<status no="0" />
</Response>
For a specific product code I need to obtain the realm
name i.e. the inner text of:
<a name="realm" format="text">
-u@surfuk2</a>
Because every element name is either <block>
or <a>
it's a bit troublesome to parse with linq to xml or query expressions.
Is the following the most effective/efficient/expressive way to get at the realm name for a specific product, e.g. 1235:
List<XElement> products = response
.Element("Response")
.Elements("block")
.Where(x => x.Attribute("name").Value == "products")
.Elements("block").ToList();
//
// I broke down the query to aid readability
//
string realm = products.Elements("a")
.Where(x => x.Attribute("name").Value == "product-id")
.Where(y => y.Value == "1235") // hardcoded for example use
.Ancestors()
.First()
.Elements("block")
.Where(z => z.Attribute("name").Value == "realms")
.Elements("block")
.Elements("a")
.First().Value;
Upvotes: 5
Views: 653
Reputation: 243599
The definition of realm
as provided is the equivalent of the simpler:
string realm = (string) products.XPathEvaluate(
"string(
/*/blocks[@name='products']
/*/a[@name='product-id' and . = '1236']
/following-sibling::block[1]
)
"
)
This in fact is both more readable and more compact than the definition of realm
provided in the original question.
As efficiency is concerned, it could well be that evaluating a single XPath expression may turn out to be more efficient, too, however to find if this is true we need to write an application that will compare the timings of the two methods.
Upvotes: 2
Reputation: 41690
It seems so, but why do you need all of the ToList()
calls? I see three of these calls and I don't think they're needed so they simply slow down your code. But then again, I've not used much Linq-to-XMl.
Upvotes: 0