XPath greater than operator? - xpath

I'm trying to select all event log entries beyond a certain date. So far I think I got equals, but I don't know how to change this to greater than the specified date... so close yet so far!
<QueryList>
<Query Id="0" Path="Application">
<Select Path="Application">*[System[TimeCreated[#SystemTime='2013-01-01T12:21:25.0000000']]]</Select>
</Query>
</QueryList>

I found the best way to create a XPath query for EventLog. See here on how to create a custom view. After you create the custom view, with whatever filter you want, simply click on the XML, and voila, it shows you the XPath query that it constructed itself!
The next challenge was the formating of the date. I used this: "yyyy-MM-ddThh:mm:ss:fffZ"
I also think you cannot create a filter that says, shows me everything after this date. So I simply recreated a range between the date I wanted and the current date.
For completeness, here is the filter that I created (who dreams up specs for this?)
<QueryList>
<Query Id="0" Path="Application">
<Select Path="Application">*[System[(Level=1 or Level 2 or Level=3) and TimeCreated[#SystemTime>='2013-01-01T12:00:00:000Z' and #SystemTime<='2013-02-13T05:30:34:948Z']]]</Select>
</Query>
</QueryList>

Use something like this:
*[System[TimeCreated[
number(translate(substring-before(#SystemTime, 'T'), '-', '')) > 20130101]]]
If you need to consider the entire string, then strip everything unnecessary to the comparison:
*[System[TimeCreated[
number(translate(#SystemTime, '-T:.', '')) > 201301011221250000000]]]

Related

It is possible to use Xpath function in order to read the date value

Since i am new to Xpath i want to ask if it is possible to use Xpath function in order to read the date value in the following
<div id="qa-case">
<time itemprop="datePublished" datetime="2015-01-12T02:41:00Z"></time>
</div>
What I want is the value in the datetime. Is that possible to read it using something like this
//*[#id="qa-case"]fn:string(datetime)
What i expect is to have an text showing me 2015-01-12T02:41:00Z
Thanks in advance
We do not know what version of XPath you are using. In XPath 1.0, functions must be wrapped around everything else because they cannot be steps in a path expression:
string(//div[#id = 'qa-case']/time/#datetime)
This only works with exactly one time element node and thus with one datetime attribute.
In XPath 2.0 you could also do
//div[#id = 'qa-case']/time/#datetime/string()
The result, in both cases, is
2015-01-12T02:41:00Z
To give a more specific answer, we would need to know more about the environment you use XPath in (say, XSLT).
To get just the text, you don't really need any date functions, just //div[#id="qa-case"]/#datetime
If you want to convert to a more readable format you cna then use date-specific XPath functions, for example:
<p>Today is <xsl:value-of="fn:day-from-dateTime(#datetime)" </p>

Xpath query for event filtering

I have the current filtering logic to define events that I want to source
<QueryList>
<Query Id="0" Path="Security">
<Select Path="Security">
*[System[(EventID=4624 or EventID=4625)]]
and
*[EventData[Data[#Name='TargetUserName'] != 'ANONYMOUS LOGON']]
and
*[substring([EventData[Data[#Name='TargetUserName']]],2,1) != '-']
</Select>
</Query>
</QueryList>
But THe part "*[substring([EventData[Data[#Name='TargetUserName']]],2,1) != '-']" is leading to error as it is not being parsed.
I want to discard certain target usernames which start with 'L-' and 'D-' and 'C:/'.
Please suggest proper solutions
I am guessing, based on how you wrote your third XPath expression, that you have a structure like this:
...
<Any-Element>
<EventData>L-username
<Data Name='TargetUserName'>xxx</Data>
</EventData>
</Any-Element>
...
Then you could use this expression to obtain what you want:
*[substring(EventData[Data[#Name='TargetUserName']], 2, 1) = '-']
But I suspect this is not the case, since your second expression compares the contents of the <Data> element (and not the contents of <EventData>, and you didn't mention it was failing. So probably the xxxstring above is where your username is. If that is the case, you should compare the contents of Data, and not EventData:
*[EventData[substring(Data[#Name='TargetUserName'], 2, 1) = '-']]
I found that if you change the query to pull application or system logs that you do not get the same error. There seems to be a bug with the Security logs. Another post suggests that reducing the character length to under 150 seems to resolve the issue.
https://social.technet.microsoft.com/Forums/windowsserver/en-US/cda721cc-6479-4b04-9fdd-9ccbec86b159/possible-bug-collecting-security-events-using-event-subscriptions-and-windows-2008-r2?forum=winserverManagement
Not sure if this solves your problem as you may need more than 150 characters.

How do I select an item from a drop down with Site Prism?

I have the following elements defined within a SitePrism page:
element :type, "select[id='type']"
elements :type_options, "select[id='type'] option"
And in my cucumber step definitions I have the following code to select an item from the select box based on the elements value:
#app.new.type_options.each {|name| name.click if name.text.upcase == value.upcase}
I don't really like this implementation but it does work perfectly when running Capybara in chrome but fails when I run it headless so I figure there must be an alternate / better way to select drop down items.
Ideally I'd like to be able to do something like #app.new_r.r_type.select 'value', but I can't work out how to do this in SitePrism.
So, my first question is, can anyone recommend an elegant way to select an item from a drop down based on value from SitePrism?
And my second question is, any idea why the above code fails when running headless?
I had a similar problem, where I couldn't get it to select the option I wanted. I came across this question and it made me realize my problem was that you have to send the text, not the value, to the select().
For example, if I have HTML like
<select id="things">
<option value="thing1">The First Thing</option>
<option value="thing2">The Second Thing</option>
<option value="thing3">The Third Thing</option>
</select>
And in my SitePrism::Page class I have:
element :things, "select[id='things']"
I thought I needed to do:
#my_page.things.select("thing1")
That does not work. Instead you have to do:
#my_page.things.select("The First Thing")
I know this is slightly different than trying to select based on a value you get from SitePrism, like was originally asked. But I thought this distinction about what to pass to select() might help someone.

How can I do a wildcard search with Nokogiri?

I'm trying to get rid of all data- attributes in a document. If my document looks like
<div id="person" data-name="John Smith" data-age="32" data-location="UK">...</div>
I want to strip out the data to just leave
<div id="person">...</div>
I've tried a lot of combinations, and can a least get to things like data-name with
doc.xpath('//#data-name')
but sometimes, there will be more data-? properties, and I'd like to avoid manually adding them all. This SO answer is close, but it's not returning anything for me when I try
doc.xpath("//*[#*[contains(., 'data-')]]")
To select all attributes whose name starts with data-:
//#*[starts-with(name(), 'data-')]
That answer you found was too deeply nested, try it this way:
doc.xpath('//*[contains(., "data-")]')

XPath concat multiple nodes

I'm not very familiar with xpath. But I was working with xpath expressions and setting them in a database. Actually it's just the BAM tool for biztalk.
Anyway, I have an xml which could look like:
<File>
<Element1>element1<Element1>
<Element2>element2<Element2>
<Element3>
<SubElement>sub1</SubElement>
<SubElement>sub2</SubElement>
<SubElement>sub3</SubElement>
<Element3>
</File>
I was wondering if there is a way to use an xpath expression of getting all the SubElements concatted? At the moment, I am using:
/*[local-name()='File']/*[local-name()='Element3']/*[local-name()='SubElement']
This works if it only has one index. But apparently my xml sometimes has more nodes, so it gives NULL. I could just use
/*[local-name()='File']/*[local-name()='Element3']/*[local-name()='SubElement'][0]
but I need all the nodes. Is there a way to do this?
Thanks a lot!
Edit: I changed the XML, I was wrong, it's different, it should look like this:
<item>
<element1>el1</element1>
<element2>el2</element2>
<element3>el3</element3>
<element4>
<subEl1>subel1a</subEl1>
<subEl2>subel2a</subEl2>
</element4>
<element4>
<subEl1>subel1b</subEl1>
<subEl2>subel2b</subEl2>
</element4>
</item>
And I need to have a one line code to get a result like: "subel2a subel2b";
I need the one line because I set this xpath expression as an xml attribute (not my choice, it's specified). I tried string-join but it's not really working.
string-join(/file/Element3/SubElement, ',')
/File/Element3/SubElement will match all of the SubElement elements in your sample XML. What are you using to evaluate it?
If your evaluation method is subject to the "first node rule", then it will only match the first one. If you are using a method that returns a nodeset, then it will return all of them.
You can get all SubElements by using:
//SubElement
But this won't keep them grouped together how you want. You will want to do a query for all elements that contain a SubElement (basically do a search for the parent of any SubElements).
//parent::SubElement
Once you have that, you could (depending on your programming language) loop through the parents and concatenate the SubElements.

Resources