I have a function that takes the result set as element and a string as args and I want to use this string as a selector inside the function.
function abc ($results as element()*, $element as xs:string)
{
for $g in distinct-values($results//*[name() = $element]) (: $results//genre :)
let $c := //$results[? = $g] (: //$results[genre=$g] :)
}
what should be in place of '?' in variable '$c'
function abc ($results as element()*, $element as xs:string)
{
for $g in distinct-values($results//*[name() = $element]) (: $results//genre :)
let $c := //$results[? = $g] (: //$results[genre=$g] :)
}
what should be in place of '?' in
variable '$c'
It is a syntax error to write:
//$results
This question is rather vague, but it seems to me that you want to group the elements, contained in $results according to their genre (or whatever element name defined by $element -- BTW this name sucks (an element isn't a string) -- better use $elementName).
The other concerning fact is that you check the complete subtrees topped by each of the elements in $results -- this means that they may have multiple genre (or whatever) descendents.
To finalize my guessing spree, it seems to me that you want this:
function grouping-Keys ($elems as element()*, $subElementName as xs:string) as element()*
{
for $g in distinct-values($elems//*[name() = $subElementName ])
return
$elems[//*[name() = $subElementName ] = $g][1]
}
If it is known that $subElementName is a name of a child that any of the elements in $elems have, then the above should be better written as:
function grouping-Keys ($elems as element()*, $childElementName as xs:string) as element()*
{
for $g in distinct-values($elems/*[name() = $childElementName ])
return
$elems[/*[name() = $subElementName ] = $g][1]
}
Both of the above functions return one element per a (distinct value of) genre (or whatever). If it is known (guaranteed) that every element in $elems has exactly one child (descendent) named genre (or whatever), then the results of these functions are not redundant.
Related
I want to safe IDs in a map. If the ID occurs again, I want to set the count ($value) from 1 to 2 and so on.
Following you find my code:
declare namespace functx = "http://www.functx.com";
declare variable $idMap := map{};
declare function functx:uniqueID ($entityID as xs:string) as xs:integer {
let $idMap := map:merge(($idMap, if(not(map:contains($idMap, $entityID))) then map:entry($entityID, 1) else map:entry(entityID, map:get($idMap, $entityID)+1)))
return map:get($idMap, $entityID)
};
declare variable $map := map:merge((
map:entry("Sheff", "85246525"),
map:entry("Peter", "85246454"),
map:entry("Marcel", "85246525"),
map:entry("Lion", "85244565"),
map:entry("Klaus", "85241234")
));
map:for-each($map,
function($key, $value) {
functx:uniqueID($value)
}
)
Result:
1
1
1
1
1
Expected Result
1
1
2 (: Because it is the second time, that 85246525 occurs. :)
1
1
Edited 23.03.2020 - 17:45:
I have a complex xquery, which functions. But the target system need unique IDs per line. I have a map, which hold my information like the upper one. I need to add something behind the IDs like (001, 002, 003) to have different IDs.
Best practice would be, that only douplicate IDs get a added number.
Do you understand or what do you need more from me?
One way to construct a new map with an "index" added to duplicated values is to use grouping:
map:merge(
for $key in map:keys($map)
group by $value := $map($key)
for $group-key at $pos in $key
return map:entry($group-key, $value || '-' || format-integer($pos, '000'))
)
At https://xqueryfiddle.liberty-development.net/6qVSgeT that gives
{
"Peter": "85246454-001",
"Marcel": "85246525-001",
"Sheff": "85246525-002",
"Lion": "85244565-001",
"Klaus": "85241234-001"
}
You've written your code as if $idMap is mutable, and as if calling functx:uniqueID() has the side-effect of modifying the map. That isn't going to work in a functional language.
You need a completely different approach; and to help you with that, we need to look at the problem you are trying to solve, not at your existing approach to a solution.
my code:
$atts->each(function($row){
if($row->key == 30){
$flag = $row->value;
echo $flag;
}
});
The value of $flag will be printed to the site. However, when I try to use the variable $flag outside the loop the variable is unknown.
Can someone tell me what I am missing or what has to be done to have access to that variable?
Thanks in advance!
Regards,
Andreas
You would need to define that variable in the current scope and import that variable into your callback's scope with use.
$flag = null;
//Access flag by reference
$atts->each(function($row) use (&$flag) {
...
});
Since we're using Laravel Collections, I suggest you not use each() for this.
if ($row = $atts->where('key', 30)->first()) {
$flag = $row->value;
}
This assumes there is only one row with a key of 30 though.
I am facing a problem with a PowerShell variable.
My scenario is,
Inside a function, I declare a variable $a, than in a switch, I get a value and store this to variable $a.
Now in another switch in that function, I want to compare $a. But there $a returns null.
Sample code is given below:
function fun
{
[CmdletBinding()]
Param (
[Parameter(Mandatory = $true, Position = 0)]
[ValidateNotNullOrEmpty()]
$param
)
$Get_OldData = " " #declare variable
switch ($param){
'param_001' {
$Get_OldData = "test data returned"
}
Default {
$Get_OldData = "test data returned"
}
}
switch ($param){
'param_001' {
$New_Data = "New Data"
#problem is here, can not compare $Get-OldData returns null here
#though data is assigned
if ( $New_Data -eq $Get_OldData){
#logic goes here
}
}
Default {
$New_Data = "New Data"
}
}
}
What is the solution of this problem?
You have multiple issues with your code.
The main issue probably is that you are using $param within your switch which has not been set. Same applies to $Fetch. Another Issue is that your $New-Data variable contains a hypen which you either should replace with an underscore or surround with curly brackets like ${New-Data}.
Also, // does not introduce a comment, you have to use a hash #.
Let's assume I have a XML files, one like this:
<SampleF>
<FirstNode AAA="Something" BBB="Something"></FirstNode>
<SecondNode CCC="Random" DDD="Random"></SecondNode>
</SampleF>
And second one like this:
<SampleF2>
<FirstNode>
<AAA>Something</AAA>
<BBB>Random</BBB>
</FirstNode>
</SampleF2>
And I would like to obtain from both (AAA="Something"/Something) of them as element(). How do I convert it? When in first case I get xs:string and in the second document-node().
I made something like this for the first example but I'm 100% certain there is a better way of doing this
declare function getElementFirstExample($message) as element() {
let $name := "AAA"
let $value := $message/*:SampleF1/*:FirstNode/#AAA
return element {$name} {"$value"}
};
Thank you in advance for your help and advices.
As I understand, you want the value of <FirstNodes/>s AAA attribute or child element, no matter whether it is in the element or attribute.
Use an alternative axis step for accessing both the attribute and element, and data(...) to retrieve the string value.
data(//FirstNode/(#AAA, AAA))
Putting this together for your function and explicit use case:
declare function getElementFirstExample($message) as element() {
let $name := "AAA"
let $value := data($message/*:SampleF1/*:FirstNode/(#AAA, *:AAA))
return element {$name} {"$value"}
};
I want to succed with following functionality, and it works if you harcoded it:
declare function local:sort($collection as node()*, $filter as xs:SUBPATH?) as node()*{
for $element in $collection
order by
if ($filter) then ($element/$filter) (: OR SOME KIND OF fn:eval($filter) IF WE DEFINED $filter AS AN xs:string :)
else ($element/name()) (: Default :)
descending
return $element
};
And it could be called like that:
for $element in local:sort(doc('data')/Data/*,'/#myAttr')
return $element
or
for $element in local:sort(doc('data')/Data/*,'/subnode/subnode/name()')
return $element
or
for $element in local:sort(doc('data')/Data/*,()) (: This is the default of function = own elmentĀ“s name :)
return $element
Mx problem is passing the subpath. Either I need to know some kind of way to send a relative XPATH as an argument and type of node, or I need some kind of eval to pass from xs:string to a runtime valid code
Any help?
You could consider (a) generating a query in which the filter is hard-coded, or (b) using an eval() function specific to your XQuery vendor, or (c) using XQuery 3.0 higher-order functions if your chosen XQuery engine supports them yet.
I ended up doing the following, thanks to this idea How can I solve this autoncremental var case in XQUERY 1.0 FLOWR?:
(: This is a workaround solution as xquery:eval() is not working with var bindings until BaseX 7.3 version :)
(: It evals $context node + literal subpath with a pattern of '(/)lit/lit/lit/#attr' or '(/)lit/lit/lit' representing (/)lit/lit/lit/name(). If subpath null, it returns $context/name().:)
declare function u:eval-path($context as node()*, $subnodes as xs:string*) as item()* {
if(empty($subnodes)) then $context/name()
else(
if (count($subnodes) eq 1) then ( (: Last Element :)
if (starts-with($subnodes[1],'#')) then $context/#*[name()=substring-after($subnodes[1],'#')]
else $context/*[name()=$subnodes[1]]/name()
)
else if ($subnodes[1] eq '') then u:eval-path($context, $subnodes[position() gt 1])
else u:eval-path($context/*[name()=$subnodes[1]],$subnodes[position() gt 1])
)
};
(: Sorts the given collection by given criteria, which should be a pattern '(/)lit/lit/lit/#attr' or '(/)lit/lit/lit' representing (/)lit/lit/lit/name() :)
(: If criteria is null, everything is ordered by $elements/name(). Theres no way to filter intermediate nodes as in /lit/*[name()='X']/lit :)
declare function u:sort($collection as node()*, $criteria as xs:string?) as node()*{
for $element in $collection
order by u:eval-path($element,tokenize($criteria,'/'))
ascending
return $element
};