Very complicated XQuery transformation - xquery

I have a very complex XQuery to write (at least by my standards).
Here is my input xml:
<testRequest>
<request1>
<Line>1</Line>
<action>addtoName</action>
</request1>
<request2>
<Line>2</Line>
<action>addtoSpace</action>
</request2>
<request3>
<Line>3<Line>
<action>addtospace</action>
</request3>
</testRequest>
In my output xml, the actions should be attached as attributes to the "request1" elements. So, based on the action element under a request1 element, the attribute for the request1 element should be one of the following:
if action = IgnoreCase(addtoName), the request1 element should be <request1 action=insertingname>
if action = IgnoreCase(addtoSpace), the request1 element should be <request1 action=updatingspace>
Not only this, but also, I need to add an attribute to the element, based on the action values underneath it.
So, I have to traverse each of the elements under a element and see if any of the elements are equal to "addtospace" if yes, then I need to get the corresponding values of the elements and make up the attribute for the element. From the above xml, my attribute for the element should be,
<testRequest lineFiller="Line Like 2_* AND Line Like 3_*>, where 2 and 3 are the respective line numbers.
and if there are no elements with element= addtoSpace, then the attribute for the element should be "changed".
So, in summary, my transformed xml should look like this:
<testRequest lineFiller="Line Like 2_* AND Line Like 3_*>
<request1 action=insertingname>
<Line>1</Line>
<action>addtoName</action>
</request1>
<request2 action=updatingspace>
<Line>2</Line>
<action>addtoSpace</action>
</request2>
<request3 action=updatingspace>
<Line>3<Line>
<action>addtospace</action>
</request3>
</testRequest>
Any help to accomplish this humungous task will be greatly appreciated.
thanks!!!

You should define functions to generate the attributes that you need to add to your elements.
For adding to the "request" element, this should work:
declare function local:getaction($x) {
if (lower-case($x/action) = "addtoname") then attribute action {"insertingspace"} else
if (lower-case($x/action) = "addtospace") then attribute action {"updatingspace"} else
()
};
The linefiller attribute can be created similarly:
declare function local:getfiller($x) {
attribute lineFiller {
if ($x/*[lower-case(action) = "addtospace"]) then
string-join(
for $r in $x/*[lower-case(action) = "addtospace"]
return concat("Line Like ",$r/Line,"_*")
, " AND ")
else "change"
}
};
Then to put it all together, fun a simple for loop over your original document, adding in the attributes where needed:
let $doc:=<<your original document>>
return
<testRequest>
{ local:getfiller($doc) }
{ for $r in $doc/* return
element { name($r) } {
local:getaction($r),
$r/*
}
}
</testRequest>
EDIT: enhanced getfiller function to return "change" if there are no actions

Related

One item per line (row) in timeline? - Vis.js

Is there a way to always have one item per line in the timeline? I don't want two or more items to share the same line, whatever the dates are.
Thanks.
You have to use groups, or if you're already using those for another purpose, you have to use subgroups.
Here's the official documentation for items, groups and subgroups (I'm assuming the website isn't gonna expire anytime soon... again...).
If you can use groups
Specify a different group for every item. You can set the group's content as an empty string, if you don't want to have a label for it on the left side of the Timeline.
If you want to arrange the groups in a specific way, specify an ordering function as the Timeline's options' groupOrder property. Example:
var options = {
// other properties...
groupOrder: function (a, b) {
if(a.content > b.content)// alphabetic order
return 1;
else if(a.content < b.content)
return -1;
return 0;
}
};
If you have to use subgroups
When you create an item, put it in the group it belongs to but also specify for it the subgroup property so that it's unique, like the item's id. For example, you can use the id itself, or add a prefix or suffix to it.
In the Timeline's options, set the stack and stackSubgroups properties to true.
In each group, set the subgroupStack property to true and specify an ordering function as the group's subgroupOrder property. Example:
var group = {
id: 1,
content: 'example group',
subgroupStack: true,
subgroupOrder: function(a, b) {
var tmp = a.start.getTime() - b.start.getTime();
return tmp === 0 ? parseInt(a.id) - parseInt(b.id) : tmp;
// if the start dates are the same, I compare the items' ids.
// this is because due to a bug (I guess) the ordering of items
// that return 0 in the ordering function might "flicker" in certain
// situations. if you want to order the items alphabetically in that
// case, compare their "content" property, or whatever other
// property you want.
}
};

Can I just style decimals of a number in Angular?

I am trying to style just the decimals to look just like this:
Didn't had success, I guess that I need to make my own filter, tried but didn't had success either, I guess it is because I am using it inside a state.
Here the code I am using for the number:
<h2><sup>$</sup>{{salary | number:0}}<sub>.00</sub></h2>
Inside the .app iam using this scope:
$scope.salary = 9000;
Thing is, number can be whatever the user salary is, it get the number from an input, in other places I have more numbers with decimals too.
Possible solutions:
Extract only the decimals from value and print them inside de
tag.
Use a filter to do this?
Use a directive that will split the amount and generate the proper HTML. For example:
app.directive('salary', function(){
return {
restrict: 'E'
, scope: {
salary: '#'
}
, controller: controller
, controllerAs: 'dvm'
, bindToController: true
, template: '<h2><sup>$</sup>{{ dvm.dollar }}<sub>.{{ dvm.cents }}</sub></h2>'
};
function controller(){
var parts = parseFloat(this.salary).toFixed(2).split(/\./);
this.dollar = parts[0];
this.cents = parts[1];
}
});
The easiest solution would be to split out the number into it's decimal portion and the whole number portion:
var number = 90000.99111;
console.log(number % 1);
Use this in your controller, and split your scope variable into an object:
$scope.salary = {
whole: salary,
decimal: salary % 1
}
Protip: Using an object like this is better than using two scope variables for performance

Best way to trigger a script for any change in one of several properties

When you bind a property it will be reevaluated if one of the proprieties to which is bounded is changed.
Example:
property bool test: prCond1 || prCond2 || ... || prCondN
When a condition is changed test is reevaluated.
Now... I want something similar but for triggering a javascript function:
when one of several conditions prCond1 || prCond2 || ... || prCondN is changed I want a function to be called.
If there was only one condition I could write:
onPrCond1Changed: {
functionCall()
}
But when you take into account more than one condition what is the best way to do it? Is there a standard way?
Basically I need something like this:
functionCall() if one of these changes: prCond1 || prCond2 || ... || prCondN
Where prCond's may be of different types.
A possible solution would be to group the variables into a variant list and look for changes on the list.
property var myObject = {'prop': 'value'}
property variant conditions = [prCond1, prCond2, myObj]
onConditionsChanged: {
console.log("one of the conditions have changed");
}
Note that changes in the properties of myObj will not trigger the changeEvent, unless the object itself is changed (e.g. myObj = new Object({'prop': 'newValue'}) )

Set inner HTML using QDomDocument

How can I set the inner HTML in a QDomElement?
When I’m using QWebElement I have the method QWebElement::setInnerXml, there is some similar method in QDomElement?
There's no API to "inject" XML snippets as text into a QDomDocument (or QXmlStreamWriter). One has to use the API and create the nodes programmatically.
Assuming you have a string to start with, my current solution is to generate a DOM tree from it, import that tree in a fragment, then copy those in the right place (you must have an import which is why you need an intermediate fragment. Quite unfortunate if you ask me.)
// assuming that 'n' is the node you are replacing or at least inserting after
// 'parent' is the parent of 'n'
// 'result' is the string to replace 'n' or insert after 'n'
QDomDocument doc_text("snap");
doc_text.setContent("<text>" + result + "</text>", true, NULL, NULL, NULL);
QDomDocumentFragment frag(xml.createDocumentFragment());
frag.appendChild(xml.importNode(doc_text.documentElement(), true));
QDomNodeList children(frag.firstChild().childNodes());
const int max(children.size());
QDomNode previous(n);
for(int i(0); i < max; ++i)
{
QDomNode l(children.at(0));
parent.insertAfter(children.at(0), previous);
previous = l;
}
// if you are replacing, then delete node n as well
parent.removeChild(n);
Note that the <text> tag is used so that way result does not need to be a tag, it could just be text and it will still work.
Obviously, if you have a fragment or XML from another document to start with, ignore the code that creates that code in the doc_text object.

assigning value in razor difficulty

I am having the following pice of code which is firing error
Error 1 Invalid expression term '='
#{
int Interest;
}
<td>#if (#item.interest.HasValue)
{
#Interest= #item.interest.Value.ToString("F2");
}
When declaring a variable, this variable needs to be assigned:
#{
string Interest = "";
}
and then:
#if (item.interest.HasValue)
{
Interest = item.interest.Value.ToString("F2");
}
This being said doing something like this in a view is a very bad design. I mean things like declaring and assigning variables based on some condition is not a logic that should be placed in a view. The view is there to display data. This logic should go to your controller or view model.
Inside your #if block you can address variables without the # sign.
#if (#item.interest.value) {
#item= #item.interest.Value
}
Is interpreted as:
#if (#item.interest.value) {
Write(item=);
Write(#item.interest.Value);
}
As you can see Write(item=) is not valid C# code.
You should use:
#if (item.interest.value) {
item = item.interest....
}
The reason your if (#item....) statement compiles, with the # sign. Is because you can prefix an identifier with the # to use reserved words as identifier names.
Try this:
#{
string Interest;
}
<td>#if (#item.interest.HasValue)
{
Interest= #item.interest.Value.ToString("F2");
}
By the way you are trying to assign a string (the result of ToString()) to an integer. This will not work.

Resources