How To compare 2 values in a loop in xslt - xslt

I have below Xml I have to perform XSLT transformation
I want to compare reference values in this uid CW with this uid xyz if the value matches then I have to create use the same values
otherwise i have to create new record on inside GUID='1'
Xml:
<Records count="1">
<Record GUID="1">
<Record GUID="abc" >
<Record GUID="JK">
<Item uid="CV">TAM</Item
<Item uid="CW">
<Reference>US</Reference>
</Item>
</Record>
</Record>
<Record GUID="abc">
<Record GUID="JK">
<Item uid="CV">IISSP</Item>
<Item uid="CW">
<Reference>IIORC</Reference>
<Reference>ISNAGEP</Reference>
</Item>
</Record>
</Record>
<Field guid="xyz">
<Reference>US</Reference>
<Reference>ACD</Reference>
<Reference>FEAS</Reference>
</Field>
</Record>
</Records>
Expected output is:
<Records>
<Record GUID="1">
<Record GUID="abc" >
<Record GUID="JK">
<Item uid="CV">TAM</Item
<Item uid="CW">
<Reference>US</Reference>
</Item>
</Record>
</Record>
</Record>
<Record GUID="1">
<Record GUID="abc">
<Record GUID="JK">
<Item uid="CV">IISSP</Item>
<Item uid="CW">
<Reference>IIORC</Reference>
<Reference>ISNAGEP</Reference>
</Item>
</Record>
</Record>
</Record>
<Record GUID="1">
<Record GUID="abc" >
<Record GUID="JK">
<Item uid="CV">TAM</Item
<Item uid="CW">
<Reference>ACD</Reference>
</Item>
</Record>
</Record>
</Record>
<Record GUID="1">
<Record GUID="JK">
<Item uid="CV">TAM</Item
<Item uid="CW">
<Reference>FEAS</Reference>
</Item>
</Record>
</Record>
</Record>
</Records>
How Can I write Xslt to acheive this please help me out
It should compare guid="xyz" values with uid="CW" if the value present thenit should print as it is like US is present then it should create new child record
but If value is not present then it should create new child record like ACD is not matched with value present in uid="CW" then it should create new child record in GUID="1"
it has to be one-to one mapping with GUID="1" and GUID="abc"
right now I have 3 records inside the GUID="1" in output I should get 4 records because ACD is not present
Could you please help me out?

Since your question lacks logic between source-xml xslt and expected outcome , here some hints:
/[some-filter] is a illegale expression. It needs a location-step (mostly a node()) after /, which is only a kind of step-separator
A few examples:
* = an element
Record = a Record-element
node() = any node()
/text() = a text() node
/#* = any attribute
/#id = id-attribute
I.e. in your xslt-snippet change this
<xsl:for-each select="../[#guid= 'CW']">
to this:
<xsl:for-each select="../*[#guid= 'CW']">
Beware xslt and XPath are case-sensitive.
So this xml:
<Record GUID="CW">
wil not be selected by
"*[#guid= 'CW']"
the XPath:
"../*[#guid= 'CW']"
will select first the parent of the context and for that parent the children with a #guid-attriuut with the value CW. Is that what you want?

Related

How can i modify field mask to satisfy a mask which has number of caracter not fixe?

I'm using odoo 9 and i create a field mask on partner code TVA and it works, but my problem is the structure of the code tva sometimes like "9999999 A/A/A/999" and sometimes like "999999 A/A/A/999". The difference is somtimes 7 integer caracters then an alphabetique caracter and sometimes 6 integer caracters. In general the first serial is not always fix and the widget "mask" allowed me to create fixed mask . How can i modify my mask to satisfy my needs . Any idea for help ?
partner_view.xml
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="res_partner_view_purchase_buttons_TVA_RC" model="ir.ui.view">
<field name="name">num.TVA.RC.res.partner.view.purchase.</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<xpath expr="//field[#name='website']" position="after">
<field name="CodeTVA" select="1" placeholder="Code TVA" widget="mask" mask="999999 A/A/A/999" />
<field name="RC" select="1" placeholder="Num RC"/>
</xpath>
</field>
</record>
</data>
Change your mask to specify that you need six or seven digits at the begining:
mask="9{6,7} A/A/A/999"

xsl:value-of select item in list?

apologies, not sure what this is called but I need to select the value for "City" in the xml I have below and have not found a solution.
<editorial>
<group>
<article>
<item name="Last Name">DOE</item>
<item name="First Name">John E. (Skip)</item>
<item name="Age">80</item>
<item name="City">Pawtucket</item>
<item name="State"></item>
<item name="Formerly Of"></item>
<item name="Death Date">1/11</item>
</article>
</group>
</editorial>

Count with conditions of a 2nd list

XML I: (e.g. shopping-cart, image-gallery)
<list1>
<entry>
...
<items>
<item id="1"></item>
<item id="2"></item>
<item id="3"></item>
</items>
</entry>
</list1>
XML II: (=associated items)
<list2>
<entry id="1">
...
<visibility>
<item value="public">Public</item>
</visibility>
</entry>
<entry id="3">
...
<visibility>
<item value="private">Private</item>
</visibility>
</entry>
<entry id="5">
...
<visibility>
<item value="public">Public</item>
</visibility>
</entry>
</list2>
Notice: The ID's in list2 might match or not...
How to get the count of items of list1 which have an ID in list2 and /visibility/item/#value = 'public' ?
With XSLT 1.0 you can use count(/list1/entry/item[#id = document('xml2.xml')/list2/entry[visibility/item/#value = 'public']/#id]).
With XSLT 2.0 a key
<xsl:template name="k1" match="list2/entry[visibility/item/#value = 'public']" use="#id"/>
and then
count(/list1/entry/item[key('k1', #id, document('xml2.xml'))])
makes the lookup more efficient.

XSLT 1.0: using EXSLT to get element name according to substring

I have the following XML and I want to get only the element names that start with "MBH":
<?xml version="1.0" encoding="UTF-8"?>
<GenericRecs>
<GenericRecord>
<record>
<MBH1/>
</record>
<record>
<BAL1/>
</record>
<record>
<MBH2/>
</record>
<record>
<BAL2/>
</record>
<record>
<PAY2/>
</record>
<record>
<MBH3/>
</record>
<record>
<BAL3/>
</record>
<record>
<PAY3/>
</record>
</GenericRecord>
</GenericRecs>
I have the following XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ext="http://exslt.org/common"
version="1.0">
<xsl:variable name="x" select="ext:node-set(substring(local-name(//record/child::*),1,3)='MBH')"/>
<xsl:variable name="mbh">
<xsl:for-each select="$x">
<item>
<xsl:copy>
<xsl:value-of select="local-name(.)"/>
</xsl:copy>
</item>
</xsl:for-each>
</xsl:variable>
<xsl:template match="/">
<xsl:apply-templates select="$mbh"/>
</xsl:template>
</xsl:stylesheet>
But all I get is an error "Description: Can not convert #RTREEFRAG to a NodeList!"
I am using EXSLT but I do not understand why I would get that error.
I have the following XML and I want to get only the element names that start with "MBH":
What's wrong with
<xsl:apply-templates select="//record/*[starts-with(name(), 'MBH')]" />
?
A few notes:
Use name() rather than local-name() whenever possible. There are no namespaces in your input so there is no difference between them anyway.
the child:: axis is the default. child::* is equivalent to *.
If you can do anything about it, change the input. Having <xyz1> through <xyz3> is not very clever, unless <xyz3> actually is completely different from <xyz1> (instead of merely being "the third <xyz>").
In that case <xyz num="1"> would be sensible. If they are completely different, they should not have a similar name.

Grouping XML elements using XSLT's for-each-group and group-starting-with attribute when the node set is stored in a variable

I'm processing a source HTML file that holds tabular data in an unstructured way. Basically it's a bunch of absolutely positioned divs. My goal is to rebuild some sort of structured XML data. So far, using XSLT 2.0 I was able to produce an XML looking like this:
<data>
<line top="44">
<item left="294">Some heading text</item>
</line>
<line top="47">
<item left="718">A</item> <!-- this item is a section-start -->
<item left="764">Section heading</item>
</line>
<line top="78">
<item left="92">Data</item>
<item left="144">Data</item>
<item left="540">Data</item>
<item left="588">Data</item>
</line>
<line top="101">
<item left="61">B</item> <!-- this item is a section-start -->
<item left="144">Section heading</item>
</line>
<line top="123">
<item left="92">Data</item>
<item left="144">Data</item>
</line>
</data>
However, what I need to do next is group lines into sections. Each section starts with a line whose first item's value consists of a single letter A – Z. My approach is to hold all the <line> elements in a $lines variable and then use xsl:for-each-group with group-starting-with attribute to identify the element starting a new section.
The respective XSLT fragment looks like this:
<xsl:for-each-group select="$lines/line" group-starting-with="...pattern here...">
<section>
<xsl:copy-of select="current-group()"/>
</section>
</xsl:for-each-group>
The problem is I can't figure out a working pattern to identify section starts. The best I could do was ensuring that //line/item[1]/text()[matches(., '^[A-Z]$')] works when used separately in an XPath evaluator. However, I can't seem to derive a working version to be used with group-starting-with.
Update Hence the wanted result should look like this:
<data>
<section> <!-- this section started automatically because of being at the beginning -->
<line top="44">
<item left="294">Some heading text</item>
</line>
</section>
<section>
<line top="47">
<item left="718">A</item> <!-- this item is a section-start -->
<item left="764">Section heading</item>
</line>
<line top="78">
<item left="92">Data</item>
<item left="144">Data</item>
<item left="540">Data</item>
<item left="588">Data</item>
</line>
</section>
<section>
<line top="101">
<item left="61">B</item> <!-- this item is a section-start -->
<item left="144">Section heading</item>
</line>
<line top="123">
<item left="92">Data</item>
<item left="144">Data</item>
</line>
</section>
</data>
The solution:
<xsl:for-each-group select="$lines/line" group-starting-with="line[matches(child::item[1], '^[A-Z]$')]">
<section name="{current-group()[1]/item[1]}">
<xsl:copy-of select="current-group()"/>
</section>
</xsl:for-each-group>
The trick is really understanding that group-starting-with shall be a pattern not a condition.