For example I have this XML:
<root>
<group>
<person gender="male" name="Daniel" />
</group>
<group>
<person gender="male" name="Peter" />
<person gender="female" name="Claudia" />
</group>
<group>
<person gender="female" name="Andrea" />
</group>
</root>
I want to find only groups that have a male and a female person. I just want to find:
<group>
<person gender="male" name="Peter" />
<person gender="female" name="Claudia" />
</group>
Because inside that group there is a male and a female.
I don't want to find:
<group>
<person gender="female" name="Andrea" />
</group>
<group>
<person gender="male" name="Daniel" />
</group>
I'm not entirely familiar with Nokogiri, but I do know xpath. If you want to select the group with male and females only you can do this
//group[person/#gender='male' and person/#gender = 'female']
It should return
<group>
<person gender="male" name="Peter"/>
<person gender="female" name="Claudia"/>
</group>
Related
is there a way to define a slicing based on the value of an extension on top of each element of a collection? example: Procedure.bodySite
<element id="Procedure.bodySite">
<path value="Procedure.bodySite" />
<slicing>
<discriminator>
<type value="value" />
<path value="bodySite.extension("http://a/ext").value" />
</discriminator>
<rules value="open" />
</slicing>
</element>
<element id="Procedure.bodySite.extension">
<path value="Procedure.bodySite.extension" />
<slicing>
<discriminator>
<type value="value" />
<path value="url" />
</discriminator>
<rules value="open" />
</slicing>
</element>
<element id="Procedure.bodySite.extension:myExtension">
<path value="Procedure.bodySite.extension" />
<sliceName value="myExtension" />
<type>
<code value="Extension" />
<profile value="http://a/ext" />
</type>
</element>
<element id="Procedure.bodySite:sliceBodySite">
<path value="Procedure.bodySite" />
<sliceName value="sliceBodySite" />
<max value="1" />
</element>
<element id="Procedure.bodySite:sliceBodySite.text">
<path value="Procedure.bodySite.extension" />
<fixedBoolean value="true" />
</element>
the result is : Unable to resolve discriminator in definitions: bodySite.extension('http://a/ext').value
so what is the problem here?
You can use .extension("url") as part of the path in a discriminator. So you can slice by value with a discriminator path of:
bodySite.extension("http://your/extension/url/here").value
For this XML excerpt, I would like to specify "the last inner group", in this case "Reporting" but there might be more tags in that inner area, I want the last one inside "Other Information"
So how can I say "the last inner group of page string='Other Information' "?
<page string="Other Information">
<group>
<group string="Sales Information" name="sales_person">
<field name="user_id"/>
<field name="team_id" options="{'no_create': True}"/>
<field name="client_order_ref"/>
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
<field name="project_id" attrs="{'invisible':[('state','=','sale')]}" context="{'default_partner_id':partner_invoice_id, 'default_name':name}" groups="analytic.group_analytic_accounting"/>
<field name="related_project_id" attrs="{'readonly': ['|',('project_id','!=',False),('invoice_count','!=',0),('state','=','sale')],'invisible':[('state','!=','sale')]}" context="{'default_partner_id':partner_invoice_id, 'default_name':name}" groups="analytic.group_analytic_accounting"/>
</group>
<group name="sale_pay" string="Invoicing">
<field name="fiscal_position_id" options="{'no_create': True}"/>
<field name="invoice_status" attrs="{'invisible': [('state', 'not in', ('sale','done'))]}"/>
</group>
<!-- ***** THIS ONE ****** -->
<group string="Reporting" name="technical" groups="base.group_no_one">
<field groups="base.group_no_one" name="origin"/>
</group>
<!-- ***** THIS ONE ****** -->
</group>
</page>
xpath to select last item is:
(somepath)[last()]
So #eLRuLL's answer is correct in the general case, but it's always better to keep some structure in xpath, and if you know your xml structure - say explicitly on what level you need to get tags, so in case when formating brakes - you'll know about that:
(//page[#string="Other Information"]/group/group)[last()]
or at least select only groups with names, not to get group that is a wrapper:
(//page[#string="Other Information"]//group[#name])[last()]
This should give you the last inner tag:
(//page[#string="Other Information"]//group)[last()]
The parenthesis are making sure that from all the groups, you actually get the last.
Location Path: for last node.
To select page[last]/group[last] element last child group node.
(//page[#string="Other Information"]/group)[last()]
//page[#string="Other Information"][last()]/child::group[position()=1]
//page[#string="Other Information"][last()]/child::group[position()=last()]
To select page[last]/group[last]/group[last] element.
(//page[#string="Other Information"]//group)[last()]
(//page[#string="Other Information"]/group)[last()]/child::group[position()=1]
(//page[#string="Other Information"]/group)[last()]/child::group[position()=last()]
selects the last but one para child of the context node
(//page[#string="Other Information"]/group)[last()]/child::group[position()=last()-1]
(//page[#string="Other Information"]/group)[last()]/child::group[position()=last()]/preceding-sibling::*[1]
child node with [attribute::type="warning"]
(//page[#string="Other Information"]/group)[last()]/child::group[position()=last()][attribute::string="Reporting"]
TestXML:
<page string="Other Information">
<!-- page[last]/group[last] -->
<group>
<group string="Sales Information" name="sales_person">
<field name="user_id"/>
<field name="team_id" options="{'no_create': True}"/>
</group>
<group name="sale_pay" string="Invoicing">
<field name="fiscal_position_id" options="{'no_create': True}"/>
</group>
<!-- page[last]/group[last]/group[last] -->
<group string="Reporting" name="technical" groups="base.group_no_one">
<field groups="base.group_no_one" name="origin"/>
</group>
</group>
</page>
I am using an XQUERY FLWOR expression into an .xml file:
for $dynosaur in doc("document.xml")//species
let $dynosaurName := $dynosaur/text() // keeping the dynosaurName as a variable
return $dynosaur
The above return results like:
<species age="84">Velociraptor</species>
I need to format the result to be like:
<!ELEMENT dynosaur (Velociraptor) +>
so i am trying using the below but not working...
return <!ELEMENT dynosaur ({$dynosaurName}) +> //here i want that format but it return error
And the xml file:
<?xml version="1.0"?>
<dinosauria>
<group>
<name>saurishia</name>
<subgroups>
<group>
<name>theropoda</name>
<subgroups>
<group>
<name>carnosaurs</name>
<speciesList>
<species age="74">Dyptosaurus</species>
<species age="170">Megalosaurus</species>
<species age="67">Tyrannosaurus</species>
</speciesList>
</group>
<group>
<name>coelurosauria</name>
<speciesList>
<species age="84">Velociraptor</species>
<species age="110">Deinonychus</species>
<species age="228">Eoraptor</species>
</speciesList>
</group>
</subgroups>
</group>
<group>
<name>sauropodomorpha</name>
<subgroups>
<group>
<name>sauropods</name>
<speciesList>
<species age="155">Brachiosaurus</species>
<species age="155">Camarasaurus</species>
</speciesList>
</group>
</subgroups>
</group>
</subgroups>
</group>
<group>
<name>ornithishia</name>
<subgroups></subgroups>
</group>
</dinosauria>
Finally:
I can't find any way to return that type of result . I have checked a lot of links considering and this book : http://www.datypic.com/books/xquery/chapter09.html
Could you try outputting text?
return concat("<!ELEMENT dynosaur (",$dynosaurName, ") +>")
I'm create simple module with 4 fields (name,date,user,description).Below is my .xml file.
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_my_report_form" model="ir.ui.view">
<field name="name">penalty.form</field>
<field name="model">my.report</field>
<field eval="2" name="priority"/>
<field name="arch" type="xml">
<form string="Project">
<sheet string="My report">
<group>
<div class="oe_title">
<h1 class="o_row">
<field name="name" placeholder="Name..." />
</h1>
</div>
</group>
<group>
<field name="user" placeholder="User..."/>
</group>
<group>
<field name="date" placeholder="Date..."/>
</group>
<notebook>
<page name="description_page" string="Description">
<field name="description"/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_my_report_form">
<field name="name">Add new</field>
<field name="res_model">my.report</field>
</record>
<menuitem name="MY report" id="menu_penalty" action="action_my_izvjestaj_form" sequence="1"/>
</data>
</openerp>
When open from menu in grid view visble is only name.
https://postimg.org/image/ccms5aww3/
How add date and user fields?
You need to declare Tree view for that model.
<!-- Tree Views BEGIN-->
<record model="ir.ui.view" id="view_my_report_tree">
<field name="name">penalty.tree</field>
<field name="model">my.form</field>
<field name="arch" type="xml">
<tree string="Project">
<field name="name"/>
<field name="user"/>
<field name="date"/>
</tree>
</field>
</record>
Is there a way I can sort an xml file base on certain attributes with Groovy?
Here's my xml
<List>
<Person name="fff"/>
<Person name="ggg">
<PhoneNum>
<AreaCode>555</AreaCode>
<Number>1234567</Number>
</PhoneNum>
</Person>
<Person name="eee"/>
<Person name="ccc"/>
<Person name="jjj"/>
<Person name="ddd">
<PhoneNum>
<AreaCode>555</AreaCode>
<Number>7654321</Number>
</PhoneNum>
</Person>
<Person name="aaa"/>
<Person name="bbb"/>
<Person name="ttt"/>
</List>
and I want the output to be
<List>
<Person name="aaa"/>
<Person name="bbb"/>
<Person name="ccc"/>
<Person name="ddd">
<PhoneNum>
<AreaCode>555</AreaCode>
<Number>7654321</Number>
</PhoneNum>
</Person>
<Person name="eee"/>
<Person name="fff"/>
<Person name="ggg">
<PhoneNum>
<AreaCode>555</AreaCode>
<Number>1234567</Number>
</PhoneNum>
</Person>
<Person name="jjj"/>
<Person name="ttt"/>
</List>
I've looked into XMLSlurper but I can't quite seem to figure out how to do this.
Here's a modification to #dmahapatro's answer that preserves the nested node structure.
import groovy.xml.MarkupBuilder
String xml = '''
<List>
<Person name="fff"/>
<Person name="ggg">
<PhoneNum>
<AreaCode>555</AreaCode>
<Number>1234567</Number>
</PhoneNum>
</Person>
<Person name="eee"/>
<Person name="ccc"/>
<Person name="jjj"/>
<Person name="ddd">
<PhoneNum>
<AreaCode>555</AreaCode>
<Number>7654321</Number>
</PhoneNum>
</Person>
<Person name="aaa"/>
<Person name="bbb"/>
<Person name="ttt"/>
</List>
'''
def rootNode = new XmlParser().parseText(xml)
rootNode.children().sort(true) {it.attribute('name')}
new XmlNodePrinter().print(rootNode)
Here's what's going on:
Using XmlParser instead of XmlSlurper generates nodes that can be printed using XmlNodePrinter.
The children of the node are sorted by name using sort {it.attribute('name')}
The true attribute to sort mutates the underlying list, which reorders the child nodes.
The XmlNodePrinter prints the re-sorted xml document to standard out.
I think there can be a groovier way than this. But this should work on a Friday. :-)
import groovy.xml.MarkupBuilder
def xml = '''<List>
<Person name="fff"/>
<Person name="eee"/>
<Person name="ccc"/>
<Person name="jjj"/>
<Person name="aaa"/>
<Person name="bbb"/>
<Person name="ttt"/>
</List>'''
def rootNode = new XmlSlurper().parseText(xml)
def writer = new StringWriter()
def mkp = new MarkupBuilder(writer)
mkp.List{
rootNode.Person.#name.list()*.toString().sort().each{
Person(name: it)
}
}
println writer