Commit Graph

331 Commits

Author SHA1 Message Date
Yorick Peterse 27d2b6c2c3 number() spec for converting empty strings. 2014-08-27 23:52:12 +02:00
Yorick Peterse 7c68f2a49b Raise for non node sets in the sum() function.
According to the XPath spec this function *can only* take node sets, nothing
else. Lets actually enforce that.
2014-08-27 23:47:19 +02:00
Yorick Peterse ac06670c24 Better conversion of types to numbers.
The XPath number() function should also be capable of converting booleans to
numbers, something it previously was not able to do. In order to do this
reliably we can't rely on the string() function as this would make it impossible
to distinguish between literal string values and booleans. This is due to
true(), which returns a TrueClass, being converted to the string "true". This
string in turn can't be converted to a float.
2014-08-27 23:38:47 +02:00
Yorick Peterse fcb28d5ae8 Specs for various XPath evaluator helper methods. 2014-08-27 23:37:12 +02:00
Yorick Peterse 022d8e0ada Extra test for sum() for default return values. 2014-08-27 23:07:38 +02:00
Yorick Peterse 30a5d01ebd Support for the XPath sum() function. 2014-08-27 23:05:04 +02:00
Yorick Peterse 585b3535b2 Support for the XPath lang() function. 2014-08-27 20:26:27 +02:00
Yorick Peterse 7c41fa814f Default attribute namespaces.
When an attribute is prefixed with "xml" the default namespace should be used
automatically. This namespace is not registered on element level by default as
this namespace isn't registered manually, instead it's a "magic" namespace. This
also ensures we match the behaviour of libxml more closely, hopefully reducing
confusion.
2014-08-27 20:24:40 +02:00
Yorick Peterse d2f991538d Support for the XPath true()/false() functions. 2014-08-27 09:37:28 +02:00
Yorick Peterse 4ef79bad90 Support for the XPath not() function. 2014-08-27 09:35:02 +02:00
Yorick Peterse e288ab88f5 Support for the XPath boolean() function. 2014-08-26 20:22:28 +02:00
Yorick Peterse 564f8859a0 Better XPath evaluation tests for numbers. 2014-08-26 20:22:18 +02:00
Yorick Peterse bcd138a15a Lexing of explicit negative/positive XPath numbers 2014-08-26 20:21:30 +02:00
Yorick Peterse 8295fa5783 Support for the XPath translate() function. 2014-08-26 18:14:44 +02:00
Yorick Peterse 7f3f626744 Support for the XPath normalize-space() function. 2014-08-26 00:06:58 +02:00
Yorick Peterse 06bed1cfdd Support for the XPath string-length() function. 2014-08-25 23:46:18 +02:00
Yorick Peterse a60057db5c Proper handling of decimals for string() calls.
When calling the string() XPath function floats with zero decimals (10.0, 5.0,
etc) should result in a string without any decimals. Ruby converts 10.0 to
"10.0" whereas XPath expects "10".
2014-08-25 23:21:36 +02:00
Yorick Peterse 6c0c5ab720 Revert "Return XPath integers as actual integers."
The particular case of string(10) having to return "10" instead of "10.0" will
be handled separately. Returning integers breaks behaviour/expectations
elsewhere.

This reverts commit 431a253000.
2014-08-25 23:14:22 +02:00
Yorick Peterse a1a2190fe2 Support for the XPath substring() function. 2014-08-25 23:13:34 +02:00
Yorick Peterse 5382891106 Support for the XPath number() function. 2014-08-25 23:13:03 +02:00
Yorick Peterse b2ca18e127 Support for the XPath substring-after() function. 2014-08-25 22:19:13 +02:00
Yorick Peterse b9cdb4a72b Support for the XPath substring-before() function. 2014-08-25 22:11:05 +02:00
Yorick Peterse 83b873e3c1 Support for the XPath contains() function. 2014-08-25 21:52:33 +02:00
Yorick Peterse 5b65d6c31a Support for the xpath starts-with() function. 2014-08-25 09:43:06 +02:00
Yorick Peterse 276a5ab83b Support for lexing empty XPath strings. 2014-08-25 09:42:51 +02:00
Yorick Peterse b688c6dc1b Support for the XPath concat() function. 2014-08-23 20:24:18 +02:00
Yorick Peterse 431a253000 Return XPath integers as actual integers.
This is to ensure that calls such as string(10) return "10" and not "10.0". It
also saves integer -> float conversions when they're not needed.
2014-08-23 20:22:58 +02:00
Yorick Peterse b316fd3e1c Support for the XPath string() function. 2014-08-22 11:06:10 +02:00
Yorick Peterse ff8a4ad3aa Ignore comment nodes in NodeSet#text. 2014-08-22 11:05:39 +02:00
Yorick Peterse 99be3182ae Support for evaluating XPath floats. 2014-08-22 10:59:03 +02:00
Yorick Peterse 6ac3408a71 Match all node types when using node()
Previously this would only match element and text nodes.
2014-08-22 10:58:36 +02:00
Yorick Peterse da09f1296c Support for using namespace-uri() with attributes. 2014-08-21 22:36:18 +02:00
Yorick Peterse 0d41693bfc Support for using name() with attributes. 2014-08-21 21:05:06 +02:00
Yorick Peterse acc056eea4 Support for using local-name() on attributes. 2014-08-21 21:03:28 +02:00
Yorick Peterse 1dd6416bea Basic support for the XPath name() function. 2014-08-21 20:47:20 +02:00
Yorick Peterse 8cc0db2283 Support for the XPath namespace-uri() function. 2014-08-21 19:02:41 +02:00
Yorick Peterse 9e20b5ca3e Support for the XPath local-name() function. 2014-08-21 10:21:02 +02:00
Yorick Peterse 2deb7a6d84 Support for the XPath id() function.
This comes with the limitation that it *always* uses the "id" attribute. This is
due to Oga not supporting DTD parsing/evaluation.
2014-08-20 21:06:35 +02:00
Yorick Peterse d351bc26cc Support for the XPath count() function. 2014-08-20 10:16:06 +02:00
Yorick Peterse 709fa365e0 XPath support for last() + evaluator docs.
I really dislike using a stack as it introduces an internal state. Sadly there
doesn't seem to be an easy way around this.
2014-08-19 22:59:26 +02:00
Yorick Peterse 423af37422 Basic support for the XPath last() function. 2014-08-18 19:00:32 +02:00
Yorick Peterse 2817784e6b Support for the XPath pipe operator. 2014-08-17 22:04:08 +02:00
Yorick Peterse d1735750c1 Only store unique nodes in XML::NodeSet.
It's called a "set" after all.
2014-08-17 22:03:44 +02:00
Yorick Peterse bb503728af XPath support for processing instructions. 2014-08-16 22:37:57 +02:00
Yorick Peterse 0d7609da88 Support for parsing XML processing instructions. 2014-08-15 22:23:26 +02:00
Yorick Peterse 8f4eaf3823 Lexing of XML processing instructions. 2014-08-15 22:04:45 +02:00
Yorick Peterse ccd95d69d8 Support for the XPath comment() test. 2014-08-15 20:49:13 +02:00
Yorick Peterse 4e8cca258c Fixed lexing of XML CDATA tags. 2014-08-15 20:47:58 +02:00
Yorick Peterse 81edce2eb8 Fixed lexing of XML comments.
The previous setup would consume too much. For example the following HTML:

    <a><!--foo--><b><!--bar--></b></a>

would result in the following T_COMMENT token:

    "foo--><b><!--bar"

The new setup requires the marking of a start position. I'm not a huge fan of
this but there doesn't appear to be a way around this.
2014-08-15 20:42:32 +02:00
Yorick Peterse 4d7f224892 Support for the XPath text() type test. 2014-08-15 10:46:00 +02:00
Yorick Peterse 14aa420091 Use a new base class for XML text nodes.
The classes Text, Cdata and Comment now extend CharacterData instead of Text.
2014-08-15 10:43:16 +02:00
Yorick Peterse 24bc84e15e Added XML::Element#text_nodes.
This method returns all the text nodes directly nested in an element.
2014-08-15 10:07:49 +02:00
Yorick Peterse d0092b434d Removed Document#available_namespaces.
Namespaces aren't scoped per document but instead per element, thus this method
doesn't make that much sense. This also fixes the remaining, failing XPath test.
2014-08-14 23:12:33 +02:00
Yorick Peterse d34e4697de Match node types in node_matches?
The method XPath::Evaluator#node_matches? now has a special case to handle
"type-test" nodes. This in turn fixes a bunch of failing tests such as those for
the XPath query "parent::node()".
2014-08-14 22:54:19 +02:00
Yorick Peterse a437d67573 Renamed node_type to type_test. 2014-08-14 22:35:41 +02:00
Yorick Peterse 05f6fc2f8d Implement node() as a type test, not a function. 2014-08-14 22:30:14 +02:00
Yorick Peterse 6ad5170476 Support for lexing/parsing XPath type tests.
Unlike what I thought before syntax such as "node()" is not a function call.
Instead this is a special node test that tests the *types* of nodes, not their
names.
2014-08-14 21:51:58 +02:00
Yorick Peterse 23441bb5a4 Basic support for the XPath node() function. 2014-08-14 18:17:08 +02:00
Yorick Peterse f2fe2a4b47 Failing XPath spec for double slashes.
The lexer doesn't lex things correctly due to "//" and "/" both being separate
rules. As a result the lexer emits two T_SLASH tokens for queries such as
".//foo".
2014-08-13 00:37:12 +02:00
Yorick Peterse f4ae83498e Eval specs for the self axis short form. 2014-08-11 09:35:01 +02:00
Yorick Peterse ffcefa92a7 Eval specs for the descendant-or-self short axis.
This currently fails due to the node() function not being implemented just yet.
2014-08-11 09:33:09 +02:00
Yorick Peterse aef3e0f27e Evaluator specs for the attribute axis short form. 2014-08-11 09:32:45 +02:00
Yorick Peterse 4d956c9ef0 Support for the XPath "namespace" axis. 2014-08-11 00:58:57 +02:00
Yorick Peterse 873bd82273 Stricted matching of namespaced elements. 2014-08-11 00:47:07 +02:00
Yorick Peterse 78da274452 Updated XPath specs for better namespace handling. 2014-08-11 00:42:06 +02:00
Yorick Peterse 33c28f633b Proper namespace support for elements.
This is still a bit rough on the edges but already way better than the broken
setup I had before.
2014-08-11 00:41:36 +02:00
Yorick Peterse 04cbbdcf9e Proper namespace support for attributes.
This separates namespace handling into namespace names and namespace objects.
The namespace objects are retrieved from the element an attribute belongs to.
Once retrieved the namespace is cached, due to the overhead of retrieving
namespaces in large documents.
2014-08-11 00:40:17 +02:00
Yorick Peterse fe8f77cf45 Basic work for supporting namespace URIs. 2014-08-08 19:03:42 +02:00
Yorick Peterse f002061aaa Extra type validation for XML::Element options. 2014-08-07 21:10:01 +02:00
Yorick Peterse b1388ff84a Ripped out inspect fuckery.
The old code used for generating Object#inspect values has been ripped out (for
the most part). The result is a non indented but far more compact #inspect
output. The code for this is also easier and doesn't break the signature of
Object#inspect.
2014-08-07 21:09:10 +02:00
Yorick Peterse 798372d099 Test for element attributes without namespaces. 2014-08-07 20:18:02 +02:00
Yorick Peterse 3b2279e410 Don't create empty Namespace nodes. 2014-08-07 20:16:46 +02:00
Yorick Peterse 97e59fe449 Use the Namespace class for namespaces vs Strings. 2014-08-07 20:03:26 +02:00
Yorick Peterse f653203220 Tests for the Namespace class. 2014-08-07 20:02:56 +02:00
Yorick Peterse 8e8ea64206 Fixed serializing of elements to XML. 2014-08-06 00:04:42 +02:00
Yorick Peterse d7df908649 Trimmed XML inspect values. 2014-08-05 23:57:12 +02:00
Yorick Peterse 26d4bdc5b1 Support for the XPath "self" axis. 2014-08-05 21:10:12 +02:00
Yorick Peterse 669ad25000 Corrected following-sibling spec description. 2014-08-05 19:28:47 +02:00
Yorick Peterse 8a9b26fa73 Basic support for the preceding-sibling xpath axis 2014-08-05 19:28:26 +02:00
Yorick Peterse e34a1ed481 Corrected specs for the "parent" xpath axis. 2014-08-05 19:26:01 +02:00
Yorick Peterse fc1d9776f3 Basic support for the XPath "preceding" axis. 2014-08-05 10:16:37 +02:00
Yorick Peterse 375f3d7870 Basic support for the XPath "parent" axis.
The usage of `parent::node()` is not yet supported.
2014-08-05 09:34:57 +02:00
Yorick Peterse a1f80b4995 Support for the "following-sibling" axis.
This also comes with some small cleanups regarding
XPath::Evaluator#node_matches?. This change removes the need to, every time,
also use can_match_node?() to prevent NoMethodError errors from popping up.
2014-08-04 21:51:51 +02:00
Yorick Peterse 57fcbbd0fc Allow Document#each_node to skip child nodes.
Child nodes can be skipped by throwing :skip_children.
2014-08-04 10:00:32 +02:00
Yorick Peterse ef1ad5406a Don't yield indexes in Document#each_node.
These indexes won't be used so there's no point in yielding them.
2014-08-04 09:08:39 +02:00
Yorick Peterse 4dc85df4e7 Corrected the XPath "following" axis specs. 2014-08-03 22:14:44 +02:00
Yorick Peterse 7fab231992 Unique spec node names for Document#each_node.
This makes it a little bit easier to see if the order is actually correct.
2014-08-01 22:09:08 +02:00
Yorick Peterse 8899542971 Better specs for Document#each_node. 2014-08-01 19:00:47 +02:00
Yorick Peterse 52a4375278 Prepare setup for *actual* following support.
The previous commit was nonsense as I didn't understand XPath's "following" axis
properly. This commit introduces proper tests and a note for future me so that I
can implement it properly.
2014-07-30 00:16:44 +02:00
Yorick Peterse 9a97d936e3 Support for the XPath "following" axis. 2014-07-29 23:09:16 +02:00
Yorick Peterse 023e7c6583 Spec for absolute XPath paths from elements. 2014-07-29 09:29:56 +02:00
Yorick Peterse 28f77b6d9b Corrected XPath attribute axis specs. 2014-07-28 00:43:52 +02:00
Yorick Peterse 23de57a3a0 Parse bare XPath node tests as child axes.
When parsing a bare node test such as "A" this is now parsed as following:

    (axis "child" (test nil "A"))

Instead of this:

    (test nil "A")

According to the XPath specification both are identical and this simplifies some
of the code in the XPath evaluator.
2014-07-28 00:34:26 +02:00
Yorick Peterse 766b35d9ce Specs for descendant-or-self. 2014-07-25 21:23:52 +02:00
Yorick Peterse 6e2be78546 Rewrote context names of some XPath specs. 2014-07-25 00:49:13 +02:00
Yorick Peterse cdf48979d5 Re-organized XPath axis evaluation specs. 2014-07-24 21:42:05 +02:00
Yorick Peterse dd37b028a0 Support for the XPath descendant axis. 2014-07-24 09:49:05 +02:00
Yorick Peterse a0ecba6321 Support for the XPath child axis. 2014-07-22 21:25:02 +02:00
Yorick Peterse ec08b41737 Specs for various XPath::Evaluator helper methods. 2014-07-22 21:04:09 +02:00
Yorick Peterse 1f9d2ede95 Skip node matching for incompatible nodes. 2014-07-22 20:45:15 +02:00
Yorick Peterse 4142504101 Revert "Lex XPath axes without a node test."
Upon further investigation this change turned out to be useless. Nokogiri/libxml
does not allow the use of long axes without tests, instead it ends up
lexing/parsing such a value as a simple node test.

This reverts commit f699b0d097.
2014-07-22 15:53:00 +02:00
Yorick Peterse c43c38fab9 Emit node() calls for certain short axes.
An axes such as "." is the same as "self::node()". To simplify things on
parser/evaluator level we'll emit the corresponding tokens for a "node()"
function call for these axes.
2014-07-22 15:50:39 +02:00
Yorick Peterse f699b0d097 Lex XPath axes without a node test. 2014-07-20 07:57:45 +02:00
Yorick Peterse 488000438b Support for querying attributes using XPath. 2014-07-20 07:47:01 +02:00
Yorick Peterse d5569ead0b Use XML::Attribute for element attributes.
Instead of using a raw Hash Oga now uses the XML::Attribute class for storing
information about element attributes.

Attributes are stored as an Array of XML::Attribute instances. This allows the
attributes to be more easily modified. If they were stored as a Hash you'd not
only have to update the attributes themselves but also the Hash that contains
them.

While using an Array has a slight runtime cost in most cases the amount of
attributes is small enough that this doesn't really pose a problem. If webscale
performance is desired at some point in the future Oga could most likely cache
the lookup of an attribute. This however is something for the future.
2014-07-20 07:29:37 +02:00
Yorick Peterse ad4d7a4744 Rewrote an attribute spec.
This way the spec doesn't depend on the attributes object being a Hash.
2014-07-19 21:07:11 +02:00
Yorick Peterse ce86785da6 Added the XML::Attribute class.
This class will replace the use of raw Hash/String values for attributes in
upcoming commits.
2014-07-16 10:08:11 +02:00
Yorick Peterse e0544959ee Specs for the ancestor-or-self axis. 2014-07-15 09:37:47 +02:00
Yorick Peterse 9a8f53bb49 Use a shared example in the axes evaluation specs. 2014-07-15 09:35:13 +02:00
Yorick Peterse 580856dcf7 Cleaned up XPath specs using a shared example. 2014-07-15 09:34:11 +02:00
Yorick Peterse 30bbd2378e Basic specs for the "ancestor" axis. 2014-07-14 00:11:03 +02:00
Yorick Peterse 56982dd543 Fail early when processing (test) nodes.
If a certain segment yields no nodes the on_path() method should not process any
following segments.
2014-07-12 00:22:18 +02:00
Yorick Peterse be4f4ad744 Trimmed the XPath AST even further.
The excessive use of (path) nodes has been dropped and all parsing conflicts
have been dealt with.
2014-07-12 00:13:25 +02:00
Yorick Peterse c89fb571db Fixed typo in the XPath evaluator's wildcard spec. 2014-07-10 10:02:21 +02:00
Yorick Peterse a61540cfc5 XPath specs for wildcard names + namespaces. 2014-07-09 23:55:09 +02:00
Yorick Peterse 8fbc582547 XPath evaluation for name/namespace wildcards. 2014-07-09 22:09:20 +02:00
Yorick Peterse ed45058983 Basic support for evaluating XPath wildcards. 2014-07-09 20:06:31 +02:00
Yorick Peterse f660b11e47 Parsing of closing XML nodes with namespaces. 2014-07-09 19:54:45 +02:00
Yorick Peterse 9c661e1e60 Added XML::NodeSet#+ and XML::NodeSet#to_a 2014-07-08 23:25:09 +02:00
Yorick Peterse 54f0355ea9 Basic specs for XPath::Evaluator.
These currently only cover very simple XPath expressions.
2014-07-08 09:40:06 +02:00
Yorick Peterse 8b381ac970 Added Node#remove.
This method can be used to remove individual nodes without first having to
retrieve the NodeSet they are stored in.
2014-07-04 10:26:41 +02:00
Yorick Peterse e334e50ca6 Added Node#previous_element and Node#next_element.
These methods can be used similar to #previous and #next expect that they only
return Element instances opposed to all Node instances.
2014-07-04 10:18:18 +02:00
Yorick Peterse 94965961ce Added XML::Element#inner_text.
This method can be used to retrieve the text of the given node only. In other
words, unlike Element#text it does not contain the text of any child nodes.
2014-07-04 09:50:47 +02:00
Yorick Peterse 8f2ecf62c6 Specs for XML::Element#text. 2014-07-04 09:45:16 +02:00
Yorick Peterse a15c19c4af Retrieving root nodes using Node#root_node.
This method uses a loop to traverse upwards the DOM tree in order to find the
root document/element. While this might have an impact on performance I don't
expect Oga itself to call this method very often. The benefit is that Node
instances don't require users to manually pass the top level document as an
argument.
2014-07-03 00:26:15 +02:00
Yorick Peterse e69fbc3ea7 Remove ownership when using NodeSet#delete. 2014-07-01 10:15:39 +02:00
Yorick Peterse 4b408eae4f Tests for Node#children=. 2014-07-01 10:09:42 +02:00
Yorick Peterse 75e96ee779 Test for Document#children= with a NodeSet. 2014-07-01 10:07:35 +02:00
Yorick Peterse 30845e3d65 Reliably remove nodes from owned sets.
The combination of iterating over an array and removing values from it results
in not all elements being removed. For example:

    numbers = [10, 20, 30]

    numbers.each do |num|
      numbers.delete(num)
    end

    numbers # => [20]

As a result of this the NodeSet#remove method uses two iterations:

1. One iteration to retrieve all NodeSet instances to remove nodes from.
2. One iteration to actually remove the nodes.

For the second iteration we iterate over the node sets and then over the nodes.
This ensures that we always remove all nodes instead of leaving some behind.
2014-07-01 09:57:43 +02:00
Yorick Peterse 8314d24435 First pass at using the NodeSet class.
The documentation still leaves a lot to be desired and so does the API. There
also appears to be a problem where NodeSet#remove doesn't properly remove all
nodes from a set. Outside of that we're making slow progress towards a proper
DOM API.
2014-06-30 23:03:48 +02:00
Yorick Peterse e71fe3d6fa Indexing of NodeSet instances.
Similar to arrays the NodeSet class now allows one to retrieve nodes for a
given index.
2014-06-29 23:59:27 +02:00
Yorick Peterse d2e74d8a0b Specs for the NodeSet class. 2014-06-26 19:52:03 +02:00
Yorick Peterse 21a0f50457 Added groups for code coverage results. 2014-06-23 09:43:41 +02:00
Yorick Peterse c840a33667 Extra tests for parsing XPath function calls. 2014-06-23 09:37:26 +02:00
Yorick Peterse d2f15e37d0 Corrected XPath operator precedence.
The previous commit didn't fully change the operator precedence according to
the XPath 1.0 specification. Also thanks to @whitequark for clearing up a few
things about Racc's operator precedence system.
2014-06-23 00:30:42 +02:00
Yorick Peterse a440d3f003 Fixed XPath operator precedence.
Apparently using multiple `left` rules with T_AND and T_OR being separate
solves this problem. Riiiiight....
2014-06-23 00:15:43 +02:00
Yorick Peterse 6a2f4fa82d Parsing support for more XPath operators.
This still messes up some tests due to botched token precedence (by the looks
of it).
2014-06-22 21:27:53 +02:00
Yorick Peterse 514c342cab Lex wildcards as T_IDENT instead of T_STAR. 2014-06-20 20:37:34 +02:00
Yorick Peterse 497f57ccd2 Basic parser setup for XPath function calls. 2014-06-17 19:57:17 +02:00
Yorick Peterse 894de7f909 Lex all XPath expressions in a single machine.
This allows literal values such as strings and numbers to be used as function
arguments.
2014-06-17 19:56:57 +02:00
Yorick Peterse bb7af98257 Updated used ASTs for all XPath parser specs. 2014-06-17 18:51:33 +02:00
Yorick Peterse 2298ef618b Reworked handling of relative vs absolute XPaths. 2014-06-16 20:19:39 +02:00
Yorick Peterse a733869f53 Use (name) nodes for @foo axes. 2014-06-13 18:00:55 +02:00
Yorick Peterse ce23cce9bd Added XPath parser specs for all axes. 2014-06-13 16:20:53 +02:00
Yorick Peterse 3ff9057858 Renamed the XPath axes_spec file. 2014-06-13 09:32:46 +02:00
Yorick Peterse f557aaef76 Lexer specs for the various XPath axes. 2014-06-13 00:16:40 +02:00
Yorick Peterse eba2d9954d Support for parsing basic XPath expressions. 2014-06-12 00:20:46 +02:00
Yorick Peterse 70f3b7fa92 Lex XPath operators using individual tokens.
Instead of lexing every operator as T_OP they now use individual tokens such as
T_EQ and T_LT.
2014-06-09 23:35:54 +02:00
Yorick Peterse 114bc0d6e8 Upgrade to RSpec 3.0.
For this I've enabled both the old expectation and stubbing/mocking syntax. The
old syntax is much more compact and to me reads nicer. For example, consider
the following:

    lex('<foo></foo>').should == [...]

To me this reads much nicer than this:

    expect(lex('<foo></foo>')).to eq([...])
2014-06-02 12:09:38 +02:00
Yorick Peterse e11b9ed32c Basic XPath parser setup. 2014-06-01 23:02:28 +02:00