Currently I'm doing some xquery like following.
XML document:
<?xml version="1.0" encoding="UTF-8"?>
<animal>
<dog name="ada">
<color>black</color>
<byear>2012</byear>
</dog>
<dog name="bob">
<color>black</color>
<byear>2011</byear>
</dog>
<cat name="cathy">
<color>black</color>
<byear>2010</byear>
</cat>
<cat name="dione">
<color>brown</color>
<byear>2009</byear>
</cat>
</animal>
Expected output:
<?xml version="1.0" encoding="UTF-8"?>
<animal>
<color>black</color>
<dog name="ada">
<byear>2012</byear>
</dog>
<dog name="bob">
<byear>2011</byear>
</dog>
<cat name="cathy">
<byear>2010</byear>
</cat>
</animal>
My code looks like:
<animal>
{ for $a in distinct-values(//animal/*/color)
return <color>{$a}</color>
{ for $b in //animal/*[color=$a]
where $b//color="black"
return $b/* except $b/color
</animal>
and the output was good but it does not include the parent tag (e.g. <dog name="ada"> </dog>).
Besides, I had also tried something like return $b except $b/color and the output this time included parent tag however it also included the "color" on the child tag. Any idea?
In normal XQuery you cannot just return a part of a node. You either return the entire node, with all its children/descendants, or you select some of the children/descendants and return those nodes entirely.
What you can do instead is to create a new node with the same name as the old one with element {node-name(...)} {...} and then copy the children you want from the old node to the new one.
Something like:
<animal>
{ for $a in distinct-values(//animal/*/color)
return (
<color>{$a}</color>,
for $b in //animal/*[color=$a]
return element {node-name($b)} {$b / #*, $b/node() except $b/color }
)
}
</animal>
(With the XQuery Update extension you could also remove the nodes you do not want instead copying them)
Related
I wanted to change the column width of the columns in tree view. So far I have tried these solutions
Adding in the field tag: width="100px" or width="15%%"
Adding in the field tag: style="width: 100px"
But Nothing seems to work for me.
I also looking for the same question, but seems like "style" doesn't work on tree view in Odoo. Seems like the only way is to define your own css class put the fixed width then assign the class on your field in your tree view.
Check this out:
xml
<tree string="Tree String" class="my_class">
<field name="my_field" />
</tree>
css
.my_class [data-id="my_field"] {
width: 1000px;
}
Method _freezeColumnWidths() in ListRenderer computes and set the column widths in the tree view. So we can inherit that method to adjust width for specific model and field(s).
The following code works on Odoo v14 (may be both of v13 and v15), adjust column width of the field partner_id of model purchase.order in tree view.
addons/ffm2_purchase/static/src/js/fix_width_list_view.js
odoo.define('ffm2_purchase.fix_width_list_view', function (require) {
"use strict";
require("web.EditableListRenderer");
var ListRenderer = require('web.ListRenderer');
ListRenderer.include({
_freezeColumnWidths: function () {
var res = this._super();
if (this.state.model=="purchase.order") {
this.$el.find('th[data-name="partner_id"]').css({
"max-width": "100px",
"width": "100px"
});
}
return res;
}
});
});
addons/ffm2_purchase/views/templates.xml
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="assets_backend" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/ffm2_purchase/static/src/js/fix_width_list_view.js"></script>
</xpath>
</template>
</odoo>
I have a XML file that follows this DTD structure.
<!DOCTYPE report [
<!ELEMENT report (title,section+)>
<!ELEMENT section (title,body?,section*)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT body (para+)>
<!ELEMENT para(#PCDATA)>
<!ATTLIST book version CDATA #REQUIRED>
<!ATTLIST section number ID CDATA #REQUIRED>
]>
And I want to query the following two things using XQuery.
1. Get all titles that appear at least twice (two sections with same title).
for $x in /report/section/
for $y in /report/section/
where $x/#title = $y/#title
return $x/#title
2. Get the number and titles of all sections with at least 10 paragraphs in the body or 5 nested sections.
for $x in /report/section/
where $x/para >= 10 or count(/section) > 10
return <large>$x/number $x/title</large>
But my queries don't seem to be correct. I am a beginner with XQuery OR XPath, could someone tell me how to fix my queries?
Edit: Sample XML
<?xml version="1.0" encoding="UTF-8"?>
<report version = '1'>
<title>Harry Potter</title>
<section number = '1'>
<title>sec1</title>
<body>
<para>1</para>
<para>2</para>
<para>3</para>
<para>4</para>
<para>5</para>
<para>6</para>
<para>7</para>
<para>8</para>
<para>9</para>
<para>10</para>
<para>11</para>
</body>
</section>
<section number = '2'>
<title>sec2</title>
<body><para>test</para></body>
<section number = '2.1'>
<title>sec21</title>
<body>
<para>test</para>
<para>test</para>
<para>test</para>
<para>test</para>
<para>test</para>
<para>test</para>
<para>test</para>
<para>test</para>
<para>test</para>
<para>test</para>
<para>test</para>
</body>
</section>
<section number = '2.2'>
<title>sec21</title>
<body><para>test</para></body>
</section>
<section number = '2.3'>
<title>sec23</title>
<body><para>test</para></body>
</section>
<section number = '2.4'>
<title>sec24</title>
<body><para>test</para></body>
</section>
<section number = '2.5'>
<title>sec25</title>
<body><para>test</para></body>
</section>
<section number = '2.6'>
<title>sec1</title>
<body><para>test</para></body>
</section>
</section>
</report>
In your first example, there are two problems. First off, you are not getting the nested sections, because you are only iterating over the section elements that are direct children of the report element. Secondly, you are using two loops over the same content. It is possible for both $x and $y to be the same element, so the where condition will match at least once for each section. I would write it like this:
for $x in distinct-values(/report//section/title)
where count(/report//section[title=$x]) > 1
return $x
The loop gets all unique titles and loops over them (note that we use report//section to get all descendant sections). Then for each of these, we count how many times it was used keeping the ones that occurred more than once. We then return the loop variable (which is bound to the title).
Running it, we get back
sec1 sec21
In the second case, we have the same problem of not getting all descendants. We also need to take the counts. I would use
for $x in /report//section
where count($x/body/para) > 9 or count($x/section) > 4
return <large>{$x/#number} {string($x/title)}</large>
Notice that I selected $x/body/para to get the paragraphs in the section (they occur as children of the body element). This counts the direct descendants, but can be modified to get all descendants if necessary. Notice also the use of curly brackets in the direct element constructor. When we construct a direct element, all text is read literally. The curly brackets are used to evaluate an xquery expression instead of literal text.
I used the string function on the title in order to extract the text contents of the element. If we didn't do that, we would get an actual title element instead of its content (which may be a desired behavior). As we extract the number attribute, it will be a attribute on our constructed element (if we wanted it to be text, we could have applied the string function to it).
In this case, it returns
<large number="1">sec1</large>
<large number="2">sec2</large>
<large number="2.1">sec21</large>
The examples here were tested using the OP's provided XML (example.xml) using Saxon-HE 9.7.0.2J. Only the relevant parts appear above, but the complete first example ran looks like
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
declare option output:method "text";
declare context item := doc("example.xml");
for $x in distinct-values(/report//section/title)
where count(/report//section[title=$x]) > 1
return $x
and the complete second example looks like
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
declare option output:method "xml";
declare context item := doc("example.xml");
for $x in /report//section
where count($x/body/para) > 9 or count($x/section) > 4
return <large>{$x/#number} {string($x/title)}</large>
For the first example in XQuery 3.0 I would use
declare context item := doc("example.xml");
for $x in /report//section/title/data()
group by $x
where count($x) > 1
return $x[1]
In my Mobile Flex project I declare a HTTPService :
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="" >
<fx:Style>
.myClass { color: Red }
</fx:Style>
<fx:Declarations>
<fx:HTTPService id="userRequest" url="http://localhost/tabletteNR/NR.php" useProxy="false" method="POST"> // it causes an error "Impossible to resolve <fx:HTTPService> as a component implementation"
<fx:request xmlns="">
<username>a</username>
<emailaddress>b</emailaddress>
</fx:request>
</fx:HTTPService>
</fx:Declarations>
...
When I change the "fx" prefix to "s" then the error disappeared ! So why is "s" the right prefix ? However I looked the package explorer and I did not find the HHTPService inside the spark.swc folder, but I saw it inside the rpc.swc -> mx.rpc.http package. So why is it "s" the right prefix ?
The HTTPService class is in the "library://ns.adobe.com/flex/spark" library namespace; and at the top of the view tag you gave that namespace a value of s:
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="" >
This is the default, BTW, but you can change it to anything you want. In theory something like this should work:
<s:View xmlns:notfx="http://ns.adobe.com/mxml/2009"
xmlns:fx="library://ns.adobe.com/flex/spark" title="" >
<notfx:Style>
.myClass { color: Red }
</notfx:Style>
<notfx:Declarations>
<fx:HTTPService id="userRequest" url="http://localhost/tabletteNR/NR.php" useProxy="false" method="POST"> // it causes an error "Impossible to resolve <fx:HTTPService> as a component implementation"
<fx:request xmlns="">
<username>a</username>
<emailaddress>b</emailaddress>
</fx:request>
</fx:HTTPService>
</fx:Declarations>
Although it is unusual and seems like a lot of work.
The namespace URLs and the classes inside the namespace are defined in a manifest.xml file which can be created as part of the SWC. Most Flex Developer's I know do not bother to change them.
To use Spark controls, default prefix is s and to use MX controls, default prefix is mx.
xmlns:s = "library://ns.adobe.com/flex/spark"
xmlns:mx = "library://ns.adobe.com/flex/mx"
I'm trying to create an XSLT which lists out movies, and I'm styling the titles so that each title has it's own color, I then select the title with with interpolation (XPath?)
Here is the XSL file:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<head>
<title>Videos</title>
<style>
table, tr, td { border: thin black solid }
th { background-color: #AAFFAA }
.Daredevil { color: red; }
/* Look at those spaces! Hrmphf! */
.Drag Me To Hell { color: green; }
</style>
</head>
<body>
<table>
<tr><th>Movies</th></tr>
<xsl:apply-templates select="//movie"/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="//movie[not(#title=preceding::movie/#title)]">
<!-- Title should be the one of the titles in the CSS -->
<tr class="{#title}"><td><xsl:value-of select="#title"/></td></tr>
</xsl:template>
</xsl:stylesheet>
The problem however is that some movie titles contain spaces. Can I have spaces in the name? If not, are there any workarounds (besides having underscores or the like in the XML)?
Update:
Ok, I get that it's not possible. At the moment I'm using translate(#title, ' ', '-') Which works when the CSS-names are delimited by -. I would still like to know if there are any better way of doing this. :)
class="Drag me to" creates an element with three different classes.
The selector .Drag.Me.To will match elements with all three classes.
However, it will match them in any order, and won't count duplicates.
No, you cannot have spaces in CSS rule names
CSS classes / id´s cannot contain spaces.
Since a space is used to seperate different classes.
You will have to resolve to a (-)
It feels a bit odd to me to tie the CSS to the actual data content in this way. Your stylesheet seems to know in advance what it expects to find in the data file, and that feels like bad design - it should be generic. Why not introduce an indirection from movie title to CSS classes:
<xsl:variable name="movieStyles">
<movie title="Drag me to hell" css-class="hell-class"/>
<movie ...
</xsl:variable>
then <tr class="{f:css-class-for-title(#title)}" ...
where the function f:css-class-for-title uses the lookup data to map movie titles to CSS classes.
I am writing some CSS to customise the display of an XML document. Basically I want to customise the display of child elements, and render them similar to HTML OL/UL/LI elements.
My XML is structured like this:
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="style.css"?>
<transcription>
<turn>
<speaker>Speaker Name</speaker>
<clause>
text here
</clause>
<clause>
one or more clauses
</clause>
</turn>
</transcription>
My CSS looks like this:
turn {
counter-reset: item;
}
turn clause {
display:list-item;
}
clause {
content: counter(item);
counter-increment: item;
}
I am using this site: http://www.xml.com/lpt/a/401 and basically have a similar document http://www.xml.com/2000/03/29/tutorial/examples/display1.xml, the problem is that the display1.xml does not work in firefox. I do get it working in IE, Safari, Chrome etc.
Can any provide a link, or sultion that would work in firefox, as well as the other browsers?
It looks like there is some bug in the way that firefox implements the display: list-item property, specifically the passing of the counter value. I believe this gives rise to the zeros which show in firefox, but not in chrome.
My workaround is to forget about using 'display: list-item' and instead style the items directly so they appear as a list:
transcription {
counter-reset: item;
}
clause {
display:block;
margin-left:40px;
}
clause:before {
counter-increment: item;
content: counter(item) ". ";
}
this works with the following XML:
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="style2.css"?>
<transcription>
<turn>
<speaker>Speaker Name</speaker>
<clause>
text here
</clause>
<clause>
text here
</clause>
<clause>
text here
</clause>
</turn>
let me know how you get on...
AL