Is there any better way to write things like [node/text()="a" or node/text()="b"] like this [contains(arraytype("a", "b"), node/text())]? Does the array type exist in XPath and can I use it inside the contains function to write more readable code?
Thanks in advance. :)
Code :
require xpath > 1
saxon-lint --xpath '/students/student/name[text()=("A", "B")]' file.xml
Output :
<name>A</name>
Files :
<?xml version="1.0"?>
<students>
<student>
<stuId>1</stuId>
<name>A</name>
<mark>75</mark>
<result></result>
</student>
</students>
Check
saxon-lint (my own project)
Thanks #Andersson for the tip
Related
I'm trying to get with xPath the position only of the first element which has the attribute value true.
<?xml version="1.0" encoding="UTF-8"?>
<elements>
<element attribute="false"/>
<element attribute="true"/>
<element attribute="true"/>
</elements>
What I have so fare is:
head(/elements/element[#attribute='true']/position())
Result:
1
But it should be:
2
What am I doing wrong?
position() returns the position of the element in the nodelist created by the predicate, i.e. with the false excluded. Instead of position, you can e.g. count the number of preceding elemements.
For example, this works even in XPath 1.0:
1+count(/elements/element[#attribute="true"][1]/preceding-sibling::element)
I think it's (with XPath 3):
head(index-of(/elements/element/#attribute, 'true'))
saxon-lint --xpath 'count(//element[#attribute="true"]/position())' file.xml
From Michael answer:
saxon-lint --xpath 'head(index-of(/elements/element/#attribute, "true"))' file.xml
Output
2
Given the following Xpath to an element
/std:Batch/BatchSection/ContractPartner/Contractor/Contract/contractNumber
How can I print out all subelements of the node Contract
where sequenceNumber= 12345?
I tried
xmllint --xpath "string(/std:Batch/BatchSection/ContractPartner/Contractor/Contract/contractNumber[contractNumber='12345'])" test.xml
However, that is an invalid XPath expression. How to fix that?
Example input:
<std:Batch xmlns:std="http://www.test.com/contractBatch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<year>2020</year>
<batchType>3</batchType>
<runDate>2020-04-11</runDate>
<text>Datatest</text>
<jobInfo>Test</jobInfo>
<BatchSection>
<addedAtDate>2020-04-11</addedAtDate>
<ContractPartner>
<contractDealerAG>44444</contractDealerAG>
<contractorType/>
<isoCountry>NL</isoCountry>
<language>EN</language>
<Contractor>
<contractor>44444</contractor>
<Contract>
<contractor>44444</contractor>
<sequenceNumber>12345</sequenceNumber>
<info1>abcd</info1>
</Contract>
</Contractor>
</ContractPartner>
</BatchSection>
</std:Batch>
Desired output (where sequenceNumber=12345):
<Contract>
<contractor>44444</contractor>
<sequenceNumber>12345</sequenceNumber>
<info1>abcd</info1>
</Contract>
You have to deal with the dreaded namespaces, unfortunately... Try it like this:
xmllint --xpath "//*[local-name()='Contract'] [.//*[local-name()='sequenceNumber'][./text()='12345']]" test.xml
and see if it works.
I'm assuming you mean sequenceNumber, as per xml example, if that's the case then you may need to do something like this to return the node Contract:
xmllint --xpath "//sequenceNumber[.="12345"]/.." test.xml
So I have an XML file like this:
<data>
<person name="john" lastname="doe" >
<grades>
<math>90</math>
<biology>23</biology>
</grades>
</person>
.
.
I know how to query this to get the average of all the grades, but I want to take that average and put it in the exact same place that grades are in for the original xml file, replacing grades. So I would have something like:
<data>
<person name="john" lastname="doe" >
<average>56.5</average>
</person>
.
.
edit: I actually figured out a way to get the needed results internally, thanks for the suggestion to this problem though, it may help me in the future.
As mentioned in the comment, XQuery can't literally returns modified XML. You will have to recreate the XML, and this get overly complicated given a complex XML document to start.
For this fairly simple XML structure though, you can use the following XQuery to return the expected XML :
<data>
{
for $p in /data/person
let $g := $p/grades/*
return
<person>
{
$p/#*,
<average>{sum($g) div count($g)}</average>
}
</person>
}
</data>
xpathtester demo
I have an XML file:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<nodeA>
</nodeA>
<nodeB>
<nodeB></nodeB>
<nodeB></nodeB>
<nodeB></nodeB>
<nodeB></nodeB>
</nodeB>
<nodeC>
</nodeC>
</root>
I want to write an XPATH expression which will select the <nodeB> which is the parent of the other <nodeB> nodes. I tried something like
"//nodeB/nodeB/parent::nodeB"
but it also choses <nodeC> besides the one I want.
Can you please help?
thanks
mc
Try this (nodeB having a child of nodeB)
//nodeB[nodeB]
I am working with an API and want to know how I can easily search and display/format the output based on the tags.
For example, here is the page with the API and examples of the XML OUtput:
http://developer.linkedin.com/docs/DOC-1191
I want to be able to treat each record as an object, such as User.first-name User.last-name so that I can display and store information, and do searches.
Is there perhaps a gem that makes this easier to do?
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<people-search>
<people total="108" count="10" start="0">
<person>
<id>tePXJ3SX1o</id>
<first-name>Bill</first-name>
<last-name>Doe</last-name>
<headline>Marketing Professional and Matchmaker</headline>
<picture-url>http://media.linkedin.com:/....</picture-url>
</person>
<person>
<id>pcfBxmL_Vv</id>
<first-name>Ed</first-name>
<last-name>Harris</last-name>
<headline>Chief Executive Officer</headline>
</person>
...
</people>
<num-results>108</num-results>
</people-search>
This might give you a jump start:
#!/usr/bin/env ruby
require 'nokogiri'
XML = %{<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<people-search>
<people total="108" count="10" start="0">
<person>
<id>tePXJ3SX1o</id>
<first-name>Bill</first-name>
<last-name>Doe</last-name>
<headline>Marketing Professional and Matchmaker</headline>
<picture-url>http://media.linkedin.com:/foo.png</picture-url>
</person>
<person>
<id>pcfBxmL_Vv</id>
<first-name>Ed</first-name>
<last-name>Harris</last-name>
<headline>Chief Executive Officer</headline>
</person>
</people>
<num-results>108</num-results>
</people-search>}
doc = Nokogiri::XML(XML)
doc.search('//person').each do |person|
firstname = person.at('first-name').text
puts "firstname: #{firstname}"
end
# >> firstname: Bill
# >> firstname: Ed
The idea is you're looping over the section that repeats, "person", in this case. Then you pick out the sections you want and extract the text. I'm using Nokogiri's .at() to get the first occurrence, but there are other ways to do it.
The Nokogiri site has good examples and well written documentation so be sure to spend a bit of time going over it. You should find it easy going.
nokogiri is a really nice xml parser for ruby that allows you to use xpath or css3 selectors to access your xml, but its not an xml to object mapper
there is a project called xml-mapping that does exactly this, by defining xpath expressions that should be mapped to object properties - and vice versa.
This is how I did it for the Ruby Challenge using the built-in REXML.
This is basicaly the parsing code for the whole document:
doc = REXML::Document.new File.new cia_file
doc.elements.each('cia/continent') { |e| #continents.push Continent.new(e) }
doc.elements.each('cia/country') { |e| #countries.push Country.new(self, e) }
http://nokogiri.org/ is an option you should investigate