How do I parse this xml using linq? - linq

So, I need just the value of those equals that are immediately within the <and> and not within the <not>. So, I need the the following: 7942 and 6252. How do I get these?
<aaa>
<and>
<equal ident="qwe">7942</equal>
<equal ident="qwe">6252</equal>
<not>
<equal ident="qwe">1056</equal>
</not>
<not>
<equal ident="qwe">6562</equal>
</not>
</and>
</aaa>

Either this is a invalid xml, and you cannot parse it with Linq, or you have typo, and opening tag names should match closing tag names, e.g:
<aaa>
<and>
<equal ident="qwe">7942</equal>
<equal ident="qwe">6252</equal>
<not>
<equal ident="qwe">1056</equal>
</not>
<not>
<equal ident="qwe">6562</equal>
</not>
</and>
</aaa>
Parsing this xml looks like:
var xdoc = XDocument.Load(path_to_xml);
var result = xdoc.Descendants("and").Elements("equal").Select(e => (int)e);
Gives:
7942
6252
Same with XPath
var result = xdoc.XPathSelectElements("//and/equal").Select(e => (int)e);

Related

How can I use XPath to find the minimum/maximum value of an attribute for chooses group in a set of elements?

<foo>
<bar id="1" score="100" group="beginner" />
<bar id="2" score="200" group="beginner" />
<bar id="3" score="300" group="expert" />
...
</foo>
I try use like this, but something wrong (xpath 1.0)
foo/bar[#group='beginner' and not(#score<= preceding-sibling::bar/#score) and not(#score<=following-sibling::bar/#score)]
using xpath 1.0
/foo/bar[#group='beginner'][(not(preceding-sibling::bar[#group='beginner']/#score >= #score) and not(following-sibling::bar[#group='beginner']/#score > #score)) or (not(preceding-sibling::bar[#group='beginner']/#score <= #score) and not(following-sibling::bar[#group='beginner']/#score < #score))]/#score

XPath with multiple child node conditions

I'm trying to find a XPath expression, to get an elment with multiple conditions on child nodes.
Which XPath can I use to get the ball element with ART_NR = 146334 and FABRICATOR = SPALDING?
The corresponding XML:
<xml>
<ball sellCode="ABC7001" type="basket ball">
<detail>
<type>INFO</type>
<values>
<type>NUMERIC</type>
<value>146334</value>
<id>ART_NR</id>
</values>
<values>
<type>NUMERIC</type>
<value>39.99</value>
<id>PRICE</id>
</values>
<values>
<type>STRING</type>
<value>SPALDING</value>
<id>FABRICATOR</id>
</values>
<values>
</detail>
<detail>
<type>MOD</type>
...
</detail>
</ball>
<ball sellCode="ABC34564" type="golf ball">
...
</xml>
Both the following XPath expressions should work:
/xml/ball[detail[values[id='ART_NR'][value=146334]]
[values[id='FABRICATOR'][value='SPALDING']]]
/xml/ball[detail[values[id='ART_NR' and value=146334]
and values[id='FABRICATOR' and value='SPALDING']]]

Sort multiple XML by element value from another XML

Basically what I'm trying to here is to merge and sort a multiple XML by a value of an element in a reference XML using XSLT.
> <xsl:variable name="refXml"
> select="document(concat(replace($refXmlTemp,'^file:',''),'/ref.xml'))"/>
>
>
> <xsl:for-each select="for $x in
> collection(string-join(($inputDir,'select=*.xml;recurse=yes;on-error=fail'),'?'))
> return
> (if (matches($refXml/root/descendant-or-self::issue/id[normalize-space(.)=normalize-space($x/art/item/id)]/number,'\w+')
> and matches($x/art/item/title,'\w+')) then saxon:discard-document($x)
> else ())">
> <xsl:sort select="$refXml/root/descendant-or-self::issue/id[normalize-space(.)=/art/item/id]/following-sibling::number"/>
The snippet above merged all the input XML but it was not sorted.
It seems that the XSLT xsl:sortfunction will only take an effect if it will be pointed at a value inside the XML that's currently processing.
Please advise on how could i get to use the ref.xml as a reference in sorting.
Here's a sample input of ref.xml:
<root>
<issue>
<id>wlu-101</id>
<number>1</number>
</issue>
<issue>
<id>wlu-143</id>
<number>2</number>
</issue>
<issue-group>
<issue>
<id>wlu-144</id>
<number>3</number>
</issue>
<issue-group>
<issue>
<id>wlu-185</id>
<number>4</number>
</issue>
</issue-group>
</issue-group>
</root>
Replace <xsl:sort select="$refXml/root/descendant-or-self::issue/id[normalize-space(.)=/art/item/id]/following-sibling::number"/> with
<xsl:sort select="key('ref', /art/item/id, $refXml)/number"/>
after defining
<xsl:key name="ref" match="issue" use="normalize-space(id)"/>
As an alternative use <xsl:sort select="$refXml//issue[normalize-space(id)=current()/art/item/id]/number"/>.

XPath expression where attribute with a suffix matches another element's attribute w/o the suffixes?

I am looking for an XPath expression that selects the hims that have parent, gramps's with name's that have the same root name with the hims having a Jr suffix and there is a store name that looks like it is named after a gramps. In the example below that would only be Bill.
<root>
<gramps name="Bill">
<him name="Bill Jr">
<kid name="Bill III"></kid>
</him>
</gramps>
<gramps name="Tom">
<him name="Al">
<kid name="Al Jr"></kid>
</him>
</gramps>
<gramps name="Bob">
<him name="Bob Jr">
<kid name="Sam"></kid>
</him>
</gramps>
<store name="Bill's" />
<store name="Tom's" />
<store name="Pete's" />
</root>
I think this will select what you need...
/*/gramps[../store/#name=concat(#name,"'s")]/him[#name=concat(../#name,' Jr')]
This will select Bill Jr because you said you wanted to select the him.
If you want to select the gramps (Bill), just put him in a predicate...
/*/gramps[../store/#name=concat(#name,"'s")][him[#name=concat(../#name,' Jr')]]

XPath in Nokogiri returning empty array [] whereas I am expecting to have results

I am trying to parse XML files using Nokogiri, Ruby and XPath. I usually don't encounter any problem but with the following I can't make any xpath request:
doc = Nokogiri::HTML(open("myfile.xml"))
doc.("//Meta").count
# result ==> 0
doc.xpath("//Meta")
# result ==> []
doc.xpath(.).count
# result => 1
Here is an simplified version of my XML File
<Answer xmlns="test:com.test.search" context="hf%3D10%26target%3Dst0" last="0" estimated="false" nmatches="1" nslices="0" nhits="1" start="0">
<time>
...
</time>
<promoted>
...
</promoted>
<hits>
<Hit url="http://www.test.com/" source="test" collapsed="false" preferred="false" score="1254772" sort="0" mask="272" contentFp="4294967295" did="1287" slice="1">
<groups>
...
</groups>
<metas>
<Meta name="enligne">
<MetaString name="value">
</MetaString>
</Meta>
<Meta name="language">
<MetaString name="value">
fr
</MetaString>
</Meta>
<Meta name="text">
<MetaText name="value">
<TextSeg highlighted="false" highlightClass="0">
La
</TextSeg>
</MetaText>
</Meta>
</metas>
</Hit>
</hits>
<keywords>
...
</keywords>
<groups>
...
</groups>
How can I get all children of <Hit> from this XML?
Include the namespace information when calling xpath:
doc.xpath("//x:Meta", "x" => "test:com.test.search")
You can use the remove_namespaces! method and save your day.
This is one of the most FAQ XPAth questions -- search for "XPath default namespace".
If there is no way to register a namespace for the default namespace and use the registered prefix (say "x" in //x:Meta) then use:
//*[name() = 'Meta` and namespace-uri()='test:com.test.search']
If it is known that Meta can only belong to the default namespace, then the above can be shortened to:
//*[name() = 'Meta`]

Resources