Reputation: 11
I have an xml document of the following format
<MyDoc>
<People>
<Person>
<Id id = 1>
<Ownerships>
<Ownership>
<Owns companyId = 2/>
<SharesOwned> 200 </SharesOwned>
</Ownership>
<Ownership>
<Owns companyId = 3/>
<SharesOwned> 100 </SharesOwned>
</Ownership>
<Ownerships>
</Person>
<Person>
<Id id = 2>
<Ownerships>
<Ownership>
<Owns companyId = 4/>
<SharesOwned> 400 </SharesOwned>
</Ownership>
<Ownership>
<Owns companyId = 3/>
<SharesOwned> 20 </SharesOwned>
</Ownership>
<Ownerships>
</Person>
</People>
</MyDoc>
For each person I want to query the ownership where shares owned is > 150, for this I wrote the following query
for $person in doc('test.xml')//People/Person
let $ownership := $person/Ownerships/Ownership
where $ownership/SharesOwned > 150
return $ownership
After this, I expected that the query would return only ownership with company id as 2 for person 1 and company id of 4 for person 2, but it is returning all the 4 ownerships.
Is there some problem with the document structure or how should I write the query to get the desired result.
EDIT 1: If I want my expected output to be '''
<People>
<Person>
<Id id = 1>
<Ownerships>
<Ownership>
<Owns companyId = 2/>
<SharesOwned> 200 </SharesOwned>
</Ownership>
<Ownerships>
</Person>
<Person>
<Id id = 2>
<Ownerships>
<Ownership>
<Owns companyId = 4/>
<SharesOwned> 400 </SharesOwned>
</Ownership>
<Ownerships>
</Person>
</People>
''' What should the query look like?
Upvotes: 0
Views: 207
Reputation: 163342
In your query
for $person in doc('test.xml')//People/Person
let $ownership := $person/Ownerships/Ownership
where $ownership/SharesOwned > 150
return $ownership
your mistake is to use let
in the second clause, rather than for
. This binds the variable $ownership
to the set of ownerships for a given person, and the where
clause selects that $ownership
if any of the items in this set satisfy the predicate.
Personally, I find the XPath formulation of queries like this much simpler and more readable (and of course it's also available in XQuery):
doc('test.xml')//Ownership[SharesOwned > 150]
As regards your edit1, you're now constructing a tree that is a modified version of the original. This is much easier to do in XSLT than in XQuery (but of course if you're running it against a database then XQuery might be all you've got). In XSLT 3.0 it's:
<xsl:transform version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="Ownership[SharesOwned le 150]"/>
</xsl:transform>
In XQuery this is easiest to achieve using XQuery Update, if that's available to you: the syntax is
delete nodes //Ownership[SharesOwned le 150]
Upvotes: 4
Reputation: 13006
Here's your xpath
. If you want to get the Ownerships/Ownership
.
//MyDoc/People/Person/Ownerships/Ownership[SharesOwned > 150]
Upvotes: 0