M.E.
M.E.

Reputation: 5515

Xpath expression to select the last of inner tag

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>

Upvotes: 5

Views: 8439

Answers (3)

Vitaliy Moskalyuk
Vitaliy Moskalyuk

Reputation: 2583

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()]

Upvotes: 8

Yash
Yash

Reputation: 9588

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>

Upvotes: 2

eLRuLL
eLRuLL

Reputation: 18799

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.

Upvotes: 2

Related Questions