7

I have an xml database that contains films, for example:

<film id="5">
        <title>The Avengers</title>
        <date>2012-09-24</date>
        <family>Comics</family>
</film>

From a Perl script I want to find film by date. If I search films of an exacly year, for example:

my $query = "//collection/film[date = 2012]";

it works exactly and return all films of 2012 year, but if I search all film before a year, it didn't work, for example:

my $query = "//collection/film[date < 2012]";

it returns all film..

lory105
  • 6,112
  • 4
  • 31
  • 40

3 Answers3

4

Well, as usual, there's more than one way to do it. ) Either you let XPath tool know that it should compare dates (it doesn't know from the start) with something like this:

my $query = '//collection/film[xs:date(./date) < xs:date("2012-01-01")]';

... or you just bite the bullet and just compare the 'yyyy' substrings:

my $query = '//collection/film[substring(date, 1, 4) < "2012"]';

The former is better semantically, I suppose, but requires an advanced XML parser tool which supports XPath 2.0. And the latter was successfully verified with XML::XPath.

UPDATE: I'd like to give my explanation of why your first query works. ) See, you don't compare dates there - you compare numbers, but only because of '=' operator. Quote from the doc:

When neither object to be compared is a node-set and the operator is = or !=, then the objects are compared by converting them to a common type as follows and then comparing them. If at least one object to be compared is a boolean, then each object to be compared is converted to a boolean as if by applying the boolean function. Otherwise, if at least one object to be compared is a number, then each object to be compared is converted to a number as if by applying the number function.

See? Your '2012-09-24' was converted to number - and became 2012. Which, of course, is equal to 2012. )

This doesn't work with any other comparative operators, though: that's why you need to either use substring, or convert the date-string to number. I supposed the first approach would be more readable - and faster as well, perhaps. )

Community
  • 1
  • 1
raina77ow
  • 103,633
  • 15
  • 192
  • 229
1

Use this XPath, to check the year

//collection/film[substring-before(date, '-') &lt; '2012']

Your Perl script will be,

my $query = "//collection/film[substring-before(date, '-') &lt; '2012']";

OR

my $query = "//collection/film[substring-before(date, '-') = '2012']";
Siva Charan
  • 17,940
  • 9
  • 60
  • 95
0

Simply use:

//collection/film[translate(date, '-', '') < 20120101]

This removes the dashes from the date then compares it for being less than 2012-01-01 (with the dashes removed).

In the same way you can get all films with dates prior a given date (not only year):

//collection/film[translate(date, '-', '') < translate($theDate, '-', '']
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431