How to print nested xml elements? - xpath

Sample xml:
<Root>
<Customers>
<Customer>
<CompanyName>Great Lakes Food Market</CompanyName>
<ContactName>Howard Snyder</ContactName>
<ContactTitle>Marketing Manager</ContactTitle>
<Phone>(503) 555-7555</Phone>
<FullAddress>
<Address>2732 Baker Blvd.</Address>
<City>Eugene</City>
<Region>OR</Region>
<PostalCode>97403</PostalCode>
<Country>USA</Country>
</FullAddress>
</Customer>
</Customers>
</Root>
In the above xml, when I use "Customer" as the root node and xpath query as "/Root/Customers/Customer", I'm unable to print the child nodes of "FullAddress" and when I use "FullAddress" as the root node and the xpath query as "/Root/Customers/Customer/FullAddress", unable to print all the fields.
Kindly help me with the solution to print all the xml elements including the nested in a single report.

The correct XPath query is
<queryString language="XPath">
<![CDATA[/Root/Customers/Customer]]>
</queryString>
This include both of your nodes, to access the value is FullAddress node you should use XPath also in fieldDescription when you define your field, hence Address is accessed through FullAddress/Address
Example
If the field declaration of CompanyName is
<field name="CompanyName" class="java.lang.String">
<fieldDescription><![CDATA[CompanyName]]></fieldDescription>
</field>
the field declaration of for example the City is
<field name="City" class="java.lang.String">
<fieldDescription><![CDATA[FullAddress/City]]></fieldDescription>
</field>

Related

Odoo13 QWEB report pdf name

On my custom modules that generate pdf reports the field "print_report_name" not name the report. I need report name + datetime actual.
Always take the name of the "name" field from the report definition.
I used it with Odoo10CE and it works perfectly.
Maybe there is another way to do it from the v10? I found nothing in the documentation.
You have to use this tag for your custom report name print under report tag. Right now I am using basic module. You can use your custom field and model for your use.
<field name="print_report_name">'%s - %s' % (object.name, object.date_done)</field>
Block of code for your reference.
<record id="action_report_lot_label" model="ir.actions.report">
<field name="name">Lot/Serial Number (PDF)</field>
<field name="model">stock.production.lot</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">stock.report_lot_label</field>
<field name="report_file">stock.report_lot_label</field>
<field name="print_report_name">'%s - %s' % (object.name, object.date_done)</field>
<field name="binding_model_id" ref="model_stock_production_lot"/>
<field name="binding_type">report</field>
</record>

Ignoring diacritics when sorting facet values in Solr 4

Tl;dr: How can I get Solr 4 to ignore diacritics when sorting facet values?
I've added the following four documents to the "collection1" Solr core in the default Solr example:
<doc>
<field name="id">1</field>
<field name="cat">manuka</field>
<field name="cat">mystery</field>
</doc>
<doc>
<field name="id">2</field>
<field name="cat">mānuka</field>
<field name="cat">stuff</field>
</doc>
<doc>
<field name="id">3</field>
<field name="cat">management</field>
<field name="cat">stuff</field>
</doc>
<doc>
<field name="id">4</field>
<field name="cat">abc</field>
<field name="cat">stuff</field>
</doc>
The "cat" field is defined as:
<field name="cat" type="string" indexed="true" stored="true" multiValued="true"/>
and the "string" type is defined as:
<fieldType name="string" class="solr.StrField" sortMissingLast="true" />
When I do a facet query on the "cat" field, sorted by value (http://localhost:8983/solr/collection1/select?q=*%3A*&rows=0&wt=json&indent=true&facet=true&facet.field=cat&facet.sort=index), I get:
....
"facet_fields":{
"cat":[
"abc",1,
"management",1,
"manuka",1,
"mystery",1,
"mānuka",1,
"stuff",3]},
....
Note that mānuka comes after mystery. I'd like to have mānuka come after manuka and before stuff, that is, I'd like the sort to ignore diacritics including the macron.
If this was a non-facet search, it looks like I could achieve what I want by setting up Collation for a separate copy field and sort by that (I can't set up collation for the field itself because the stored data will be a binary representation of the collation key). However, it looks like this approach isn't possible for facet queries since they can only be sorted by index or count.
Am I overlooking something? Is there some trick to get this working in an environment where I do need to display the value of the "cat" field?
The question is about customizing the index-order of a facet.
Your suggestion is to use Collation. You can do this and the order of your facets will be correct. The problem is that neither CollationField nor ICUCollationField are overriding the indexedToReadable method.
The two classes cannot override indexedToReadable because in general the mapping from word to term is not invertible. But for your case possible you can implemenent a subclass of ICUCollationField which overrides indexedToReadable in a sencefull way.
Your starting point could be TestICUCollationField with
<fieldType name="sort_fr_t" class="solr.ICUCollationField" locale="fr" strength="primary"/>
...
<field name="sort_fr" type="sort_fr_t" indexed="true" stored="true" docValues="true" multiValued="true"/>
as you will see in this case the names of the facet values are very unreadable.

Ruby + Nokogiri + Xpath navigate Node_Set

<Item id="item0">
<Links>
<FirstLink id="link1" target="one"/>
<SecondLink id="link2" target="two"/>
</Links>
<Data>
<String>content</String>
</Data>
</Item>
<Item id="item1">
<Links>
<FirstLink id="link1" target="two"/>
<SecondLink id="link2" target="two"/>
</Links>
<Data>
<String>content</String>
</Data>
</Item>
I have created a Nokogiri-NodeSet with this structure, i.e. a list of items with links and data children.
How can I filter any items that don't match a certain value in the 'target'-attribute of <FirstLink>?
Actually, what I want in the end is to extract the <Data><String>-Content of every <Item> that matches a certain value in it's <FirstLink> "Target"-Attribute.
I've tried several approaches already but I'm at a loss as to how to identify an element by an attribute of it's grandchild, then extracting the content of this grandchild's parent's sibling, X(.
We can build up an XPath expression to do this. Assuming we are starting from the whole XML document, rather than the node-set you already have, something like
//Item
will select all <Item> elements (I’m guessing you already have something like that to get this node-set).
Next, to select only those <Item> elements which have <Links><FirstLink> where FirstLink has a target attribute value of one:
//Item[Links/FirstLink[#target='one']]
and finally to select the Data/String children of those nodes:
//Item[Links/FirstLink[#target='one']]/Data/String
So with Nokogiri you could use something like this (where doc is your parsed document):
doc.xpath("//Item[Links/FirstLink[#target='one']]/Data/String")
or if you want to use the node-set you already have you can use a relative expression:
nodeset.xpath("self::Item[Links/FirstLink[#target='one']]/Data/String")
I completely didn't understand what your goal is. But using a guess, I am trying to show you, how to proceed in this case :
require 'nokogiri'
doc = Nokogiri::XML <<-xml
<Item id="item0">
<Links>
<FirstLink id="link1" target="one"/>
<SecondLink id="link2" target="two"/>
</Links>
<Data>
<String>content1</String>
</Data>
</Item>
<Item id="item1">
<Links>
<FirstLink id="link1" target="two"/>
<SecondLink id="link2" target="two"/>
</Links>
<Data>
<String>content2</String>
</Data>
</Item>
xml
#xpath method with the expression "//Item", will select all the Item nodes. Then those Item nodes will be passed to the #reject method to select only those nodes, that has a node called Links having the target attribute value is "one". If any of the links, either FirstLink or SecondLink has the target attribute value "one", for that nodes grandparent node Item will be selected.
node.at("//Links/FirstLink")['target'] will give you the string say "one" which is a value of target attribute of the node, FirstLink of first Item nodes , then "two" from the second Item node. The part ['any vaue'] in node.at("//Links/FirstLink")['target']['any vaue'] is a call to the String#[] method.
Remember below approach will give you the flexibility of the use regular expression too.
nodeset = doc.xpath("//Item").reject do |node|
node.at("//Links/FirstLink")['target']['any vaue']
end
Now nodeset contains only the required Item nodes. Now I use #map, passing each item node inside it to collect the content of the String node. Then #at method with an expression //Data/String, will select the String node. Then #text, will give you the content of each String node.
nodeset.map { |n| n.at('//Data/String').text } # => ["content1"]

XPath to Select Nodes Starting with a Certain Value

Given the XML structure
<Doc>
<Other />
<Q1 />
<Q2 />
</Doc>
How can I select only nodes that begin with a "Q", e.g. /Doc/Q1 and /Doc/Q2?
It seems like this can be done with starts-with, but I have only found examples that apply starts-with to the value of the node
/Doc/*[starts-with(name(), 'Q')]

XPATH query to filter values on certain attributes only

I have following XML:
<Library>
<Item>
<Field Name="Name">smooth</Field>
<Field Name="File Type">mid</Field>
<Field Name="File Size">60026</Field>
</Item>
<Item>
<Field Name="Name">mid</Field>
<Field Name="File Type">mp3</Field>
<Field Name="File Size">4584972</Field>
</Item>
</Library>
I'd like to get all item names of items of the file type "mid". My XPATH query looks as
/Library/Item/Field
[
#Name="Name" and
(../Field[#Name="File Type" and ../Field[.="mid"]])
]
But unfortunately both items are returned from that query.
smooth
mid
Seems that the last condition is not checked against fields with the attribute "File Type" only, but all fields. Which results in a return of the name "mid", even if this item is of file type "mp3".
How can I restrict the comparison with "mid" to the value of the field with the attribute Name="File Type"?
Can anybody suggest me an XPATH syntax which works as expected?
XPath predicates can be applied anywhere, this would be more straight-forward:
/Library/Item[Field[#Name="File Type"] = "mid"]/Field[#Name="Name"]
Your own expression would be correct as
/Library/Item/Field[
#Name="Name"
and ../Field[#Name="File Type"] = "mid"
]

Resources