I am a beginner in the field of MarkLogic and need help in solving
this question with clarification please. This is an example of xml
classes. I need a function to count the number of classes a student
attends, use map
<Classes>
<Class>
<Class-name>math</Class-name>
<Student-name>Jon</Student-name>
<Student-name>Sam</Student-name>
</Class>
<Class>
<Class-name>Sciences</Class-name>
<Student-name>Jon</Student-name>
<Student-name>Jack</Student-name>
<Student-name>Nay</Student-name>
</Class>
<Class>
<Class-name>Languages</Class-name>
<Student-name>Jon</Student-name>
<Student-name>Sam</Student-name>
<Student-name>Nay</Student-name>
</Class>
</Classes>
A way to count without maps would be to collect a distinct list of Student-name, and then use those names to get a count of the Student-name elements with those names:
for $student in fn:distinct-values($Classes/Class/Student-name)
return
$student||":"||count($Classes/Class[Student-name=$student])
A way to achieve the same thing with maps would be to walk over each of the Student-name elements, putting an entry in the map that increments the current count by 1:
let $stats := map:new()
let $_ :=
for $student in $Classes/Class/Student-name
return map:put($stats, $student, 1 + (map:get($stats, $student), 0)[1])
return
map:keys($stats) ! ( .||":"||map:get($stats, .) )
Related
How to check whether list of facts contains the list of parameters or attributes present. We want a Rule where The Fact is List of Variables and the attributes which we are passing it is also list of variables. We want to check whether the the Facts contains all the variables present in the List of Attributes . And if it has all the variables matching the Fact then should execute the Action part
when
variable:Fact(names contains( ${names}))
then
System.out.println($listOfNames);
end
This is the example which I have tried. Here the Fact class has the Variable name which is List of String. And ${names} is the attribute which we are passing it as the List of String. So basically we want is that when we pass the list of names in fact it shold see whether it has the variable present from ${names} if yes then should execute. But when we pass list to attribute it gives error which is
11:21:00.868 [main] ERROR o.d.c.k.b.impl.AbstractKieProject.buildKnowledgePackages:276 - Unable to build KieBaseModel:defaultKieBase
Unable to Analyse Expression names contains ( [TaskSpecification3, TaskSpecification4]):
[Error: unable to resolve method using strict-mode: com.drool.example.Fact.TaskSpecification3()]
[Near : {... names contains ( [TaskSpecification3, TaskSpecif ....}]
^ : [Rule name='Rule1_1']
It is not able to rectify bracket, when we pass attributes in the list form it gets print with brackets which gives error.
Is there any way we can Compare that One list contains the parameters from the other List.
I don't even know where to start, that rule's syntax is so wrong.
For your actual question -- how to check if one list contains all elements of another list -- this is a straight-forward ask and there are a number of possible ways to go about it.
From your question, you have a model that looks like this:
class Fact {
List<String> names;
// getters, setters
}
You're passing a Fact instance into your rules, along with a List<String> representing target names. You want your rule to trigger when all of the names in the list in memory are present in the list of names in the fact.
Based on this, your test cases would be something like:
TC | Fact | List | Result
---|--------------------------------|------------------|-------------------
1 | Fact( names: ["A", "B", "C"] ) | List: ["A", "B"] | rule fires / match
2 | Fact( names: ["A", "B", "C"] ) | List: ["A", "D"] | no match
3 | Fact( names: ["A"] ) | List: ["A", "B"] | no match
4 | Fact( names: ["A", "B"] ) | List: ["A", "B"] | rule fires / match
As I mentioned, we can write this rule in several ways. The easiest way to go about this would be to use collect.
rule "Fact check with collect"
when
$names: List( $expected: size )
Fact( $factNames: names )
$matches: List( size == $expected ) from collect(
String( this memberOf $names ) from $factNames
)
then
System.out.println($matches);
end
What we're doing here is straight-forward. First, we get the list of names and assign it to the variable $names. We also save the length of that list to $expected. Then we extract the list of names from Fact and assign it to the variable $factNames.
Next we use collect to iterate over each name in $factNames, check that it is in the $names list, and (if it is), put it into a List called $matches. We check that $matches is the same length as the $names list -- if it is, then the rule triggers and we move to the consequences (right hand side/then.)
More info on collect: see the Drools documentation (search for "Figure 82." to jump as close as you can to the unanchored section about this operator.
If the list of names is not passed as a fact, but is part of the rule, then it simplifies the case further and you can just use in to verify.
Assuming a hard-coded list of ["A", "B", "C"]:
rule "Fact check with collect and hard-coded list"
when
Fact( $factNames: names )
$matches: List( size == 3 ) from collect(
String( this in ("A", "B", "C") ) from $factNames
)
then
System.out.println($matches);
end
Note that in addition to the actual content of the list, you also have to sub in the length of the list in the size == check.
template header
salience
names
namedTags
import com.drool.example.Fact;
import java.util.Map;
import java.util.List;
global java.util.List list;
function Boolean toCompareList(List targetList, List blackList){
Boolean flag = false;
for(Object obj: targetList){
if(blackList.contains(obj)){
flag = true;
break;
}
}
return flag;
}
template "DataWithoutNull"
rule "Rule1_#{row.rowNumber}"
salience #{salience}
dialect "java"
when
$names: Fact($listOfNames:${names})
variable:Fact(toCompareList(names,$listOfNames))
then
System.out.println($names);
end
This is the Drt which I have used. Here we have written a function to check if onle list contains all the element in other function and that function is used in the Condition part where we pass facts and parameters to that function and then it evaluate it and give the result in true or false.
If its true then the action part will be executed or will look for other condition and if false will not execute the action part.
Is this the right way to do it or is there any other method. But this works absolutely fine as we expected. If there is any other method please let me know.
I have an xml with something like that inside
<SFEvents>
<EventList>
<Event>
<ID>1111</ID>
<Type>Measurement</Type>
<TimeStamp>2015-09-28T09:50:27.514</TimeStamp>
<Space>Main_area</Space>
<SourceID>Thermometer_3</SourceID>
<Content>
<Measurement>
<!-- From B2MML standard (OpSegmentDataType) -->
<ID/>
<Description>Temperature of a power resistance</Description>
<Value>
<ValueString>100</ValueString>
<UnitOfMeasure>oC</UnitOfMeasure>
</Value>
</Measurement>
</Content>
</Event>
<Event>..</Event>
...
</EventList>
with many events and I currently try to receive with xquery all the Event nodes that have their Timestamp inside a time range
I use this code
all_xmls_String=session.execute("xquery for $b in doc('CIDEMdb/CIDEM.xml')
let $date_string as xs:string :=$b/SFEvents/EventList/Event/TimeStamp/data()
let $date as xs:dateTime := xs:dateTime($date_string)
where $date ge xs:dateTime('"+startdate+"') and $date le
xs:dateTime('"+enddate+"') return $b/SFEvents/EventList");
but I receive this error
Cannot cast xs:untypedAtomic+ to xs:string: ("2015-09-28T09:50:27.514", ...).
Any idea?
The problem is that you are iterating over the EventList document, which has a cardinality of 1, while selecting $b/SFEvents/EventList/Event/TimeStamp/data(), a sequence of TimeStamp values, and assigning it to a variable that expects a single value. Your query also returns an EventList, but you say you want to return Events.
There are several ways to do this, but the easiest way given your existing query it to simply iterate over the Event elements instead, select the single TimeStamp value, and then return the selected Events.
for $b in doc('CIDEMdb/CIDEM.xml')//SFEvents/EventList/Event
let $date_string as xs:string :=$b/TimeStamp/data()
let $date as xs:dateTime := xs:dateTime($date_string)
where $date ge xs:dateTime('"+startdate+"') and $date le xs:dateTime('"+enddate+"')
return $b
What would be the most efficient way in VBScript to iterate through an XML file.
I am looking for a way to iterate all nodes in the XML file. I cannot use XQL queries, because I really do need to iterate all nodes to check all attributes in the file.
PS: Basically I am writing a script to replace references to file paths. The problem is that these file paths can be in a big number of places. (But that's for me to find out). I only need help with the XML iterating part.
While I suspect that putting some intelligence and XPath expressions into the search would increase effiency, this
Option Explicit
Dim oXDoc : Set oXDoc = CreateObject( "Msxml2.DOMDocument" )
oXDoc.async = False
oXDoc.load "..\data\31677574.xml"
If 0 = oXDoc.ParseError Then
WScript.Echo oXDoc.documentElement.xml
walk oXDoc.documentElement, 0
Else
WScript.Echo oXDoc.ParseError.Reason
End If
Sub walk(e, i)
WScript.Echo Space(i), e.tagName
Dim a
For Each a In e.Attributes
WScript.Echo Space(i + 1), a.name, a.value
Next
Dim c
For Each c In e.childNodes
walk c, i + 2
Next
End Sub
output:
cscript 31694559.vbs
<Configuration>
<Add SourcePath="\\sample" ApplicationEdition="32">
<Product ID="SampleProductID">
<Language ID="en-us"/>
<Language ID="en-us"/>
</Product>
</Add>
</Configuration>
Configuration
Add
SourcePath \\sample
ApplicationEdition 32
Product
ID SampleProductID
Language
ID en-us
Language
ID en-us
will visit all elements and their attributes.
I have a loop for example :
for my $something ( #place[1..$#thing] ) {
}
I don't get this statement 1..$#thing
I know that # is for comments but my IDE doesn't color #thing as comment. Or is it really just a comment for someone to know that what is in "$" is "thing" ? And if it's a comment why was the rest of the line not commented out like ] ) { ?
If it has other meanings, i will like to know. Sorry if my question sounds odd, i am just new to perl and perplexed by such an expression.
The $# is the syntax for getting the highest index of the array in question, so $#thing is the highest index of the array #thing. This is documented in perldoc perldata
.. is the range operator, and 1 .. $#thing means a list of numbers, from 1 to whatever the highest index of #thing is.
Using this list inside array brackets with the # sigill denotes that this is an array slice, which is to say, a selected number of elements in the #place array.
So assuming the following:
my #thing = qw(foo bar baz);
my #place = qw(home work restaurant gym);
then #place[1 .. $#thing] (or 1 .. 2) would expand into the list work, restaurant.
It is correct that # is used for comments, but not in this case.
it's how you define a range. From starting value to some other value.
for my $something ( #place[1..3] ) {
# Takes the first three elements
}
Binary ".." is the range operator, which is really two different
operators depending on the context. In list context, it returns a list
of values counting (up by ones) from the left value to the right
value. If the left value is greater than the right value then it
returns the empty list. The range operator is useful for writing
foreach (1..10) loops and for doing slice operations on arrays. In the
current implementation, no temporary array is created when the range
operator is used as the expression in foreach loops, but older
versions of Perl might burn a lot of memory when you write something
like this:
http://perldoc.perl.org/perlop.html#Range-Operators
I want to create an array in smarty and do an append functionality in it! Like if I declare a variable in smarty template like {assign var=sizearr value=''} and then i want to append values to this in a loop, and i can access values like {sizearr.0}, how can i do that?
Use append. I'm not sure if this is also available in Smarty 2
{append var='sizearr' value='' index=0}
In smarty3 yould also use a more php-like approach:
{$sizearr[] = 'your value'}
and either loop through the array like
{foreach $sizearr as $value}
{$value#key}: {$value}
{/foreach}
or just hit a specific index:
{$sizearr[2]}
You can use this too:
{$sizearr[] = "Size value"}
Here you can see the full doc (Section Appending an array)
You can simply use the smarty built-in function append :
Now lets take this example:
{assign var="ages" value=[] }
{for $i=1 to 3}
{append var="ages" value=$i }
{/for}
In the above example we didn't specify index parameter in the append function, so the value will be appended at the end of the ages array.
Hope this is helpful for everyone.