From: Lucca Hirschi Date: Tue, 17 Jul 2012 12:57:28 +0000 (+0200) Subject: Merge branch 'lucca-tests-bench' into lucca-extentions X-Git-Tag: Core+FS+Self_tested X-Git-Url: http://git.nguyen.vg/gitweb/?p=tatoo.git;a=commitdiff_plain;h=07a2770a48f51b2e09b3be2d1608516b2377618e;hp=9e29715d08094dfad88ddb0316080ec383071536 Merge branch 'lucca-tests-bench' into lucca-extentions --- diff --git a/correct_test b/correct_test index d28ee73..ec62b8a 100755 --- a/correct_test +++ b/correct_test @@ -1 +1 @@ -./solve.native ./tests/docs/XPath-FT.xml -f ./tests/queries/XPath-FT.queries \ No newline at end of file +./solve.native ./tests/docs/XPath-FT.xml -f ./tests/queries/XPath-FT.queries 1 \ No newline at end of file diff --git a/run_tests b/run_tests index 4a26469..6ee6c55 100755 --- a/run_tests +++ b/run_tests @@ -6,4 +6,5 @@ echo "__________________________________________________________________________ echo "________________________________________________________________________________" ./test.native ./tests/docs/my.xml -f ./tests/queries/my.queries.old echo "Expected answer: 43 (the b from the second big sub-tree)." -./test.native ./tests/docs/my.xml -f ./tests/queries/my.queries.old 2> tests/results/my.result \ No newline at end of file +./test.native ./tests/docs/my.xml -f ./tests/queries/my.queries.old 2> tests/results/my.result +./test.native ./tests/docs/my.xml '/descendant::b/self::b' \ No newline at end of file diff --git a/src/asta.ml b/src/asta.ml index d866005..965486a 100644 --- a/src/asta.ml +++ b/src/asta.ml @@ -88,6 +88,14 @@ let transitions_lab asta lab = (remove_lab (SetT.elements (SetT.filter filter asta.trans_q)), (remove_lab (SetT.elements (SetT.filter filter asta.trans_r)))) +let transitions_st_lab asta q lab = + let filter (s,l,f) = q = s && QNameSet.mem lab l in + let rec remove_st_lab = function + | [] -> [] + | (s,l,f) :: tl -> f :: (remove_st_lab tl) in + (remove_st_lab (SetT.elements (SetT.filter filter asta.trans_q)), + (remove_st_lab (SetT.elements (SetT.filter filter asta.trans_r)))) + let empty = { quer = StateSet.empty; reco = StateSet.empty; diff --git a/src/asta.mli b/src/asta.mli index 7bbf13d..3fd9886 100644 --- a/src/asta.mli +++ b/src/asta.mli @@ -42,6 +42,10 @@ val transitions_lab : t -> QName.t -> (state*formula) list *(state*formula) list (** Give the list of states and formulae from queries and recognizing transitions for a given tag *) +val transitions_st_lab : t -> state -> QName.t -> formula list * formula list +(** Give the list of formulae from queries and recognizing transitions for a + given state and tag *) + val empty : t (** The empty automaton *) diff --git a/src/compil.ml b/src/compil.ml index 574485e..b15b069 100644 --- a/src/compil.ml +++ b/src/compil.ml @@ -21,6 +21,8 @@ exception Not_core_XPath let pr_er = Format.err_formatter +let ax_ (a,b,c) = a + let trans query = (* Buidling of the ASTA step by step with a special case for the last step. Then add a top most state. Each function modifies asta. *) @@ -28,16 +30,15 @@ let trans query = (* builds asta from the bottom of the query *) let rec trans = function | [s] -> trans_last s - | s :: tl -> trans tl; trans_step s + | s :: tl -> trans tl; trans_step s (ax_(List.hd tl)) | [] -> () (* Add THE top most state for top-level query (done in the end) *) and trans_init () = let top_st = Asta.new_state () in let or_top = - List.fold_left (fun acc x -> ((`Left *+ x) +| acc)) - (Formula.false_) (Asta.top_states asta) - in + List.fold_left (fun acc x -> ((`Left *+ x) +| acc)) + (Formula.false_) (Asta.top_states asta) in Asta.add_quer asta top_st; Asta.init_top asta; Asta.add_top asta top_st; @@ -46,7 +47,7 @@ let trans query = (* A selecting state is needed *) and trans_last (ax,test,pred) = - let fo_p = trans_pr pred in + let fo_p = trans_pr pred in (* TODO (if ax=Self, only q *) let q,q' = Asta.new_state(), Asta.new_state() in Asta.add_selec asta q'; Asta.add_quer asta q; @@ -60,14 +61,24 @@ let trans query = Asta.add_tr asta tr_selec true; Asta.add_tr asta tr_q true + and form_next_step ax_next top_states_next form_pred = + match ax_next with + | Self -> (form_pred) *& (* (\/ top_next) /\ predicate *) + (List.fold_left (fun acc x -> (`Self *+ x ) +| acc) + Formula.false_ top_states_next) + | FollowingSibling -> (form_pred) *& (* (\/ top_next) /\ predicate *) + (List.fold_left (fun acc x -> (`Right *+ x ) +| acc) + Formula.false_ top_states_next) + | _ -> (form_pred) *& (* (\/ top_next) /\ predicate *) + (List.fold_left (fun acc x -> (`Left *+ x ) +| acc) + Formula.false_ top_states_next) + (* Add a new state and its transitions for the step *) - and trans_step (ax,test,pred) = + and trans_step (ax,test,pred) ax_next = let fo_p = trans_pr pred and q = Asta.new_state() in let Simple label = test - and form_next = (fo_p) *& (* (\/ top_next) /\ predicat *) - (List.fold_left (fun acc x -> (`Left *+ x ) +| acc) - Formula.false_ (Asta.top_states asta)) in + and form_next = form_next_step ax_next (Asta.top_states asta) fo_p in let tr_next = (q, label, form_next) and tr_propa = (q, Asta.any_label, form_propa q ax) in Asta.add_quer asta q; @@ -92,27 +103,30 @@ let trans query = (* Builds asta for predicate and gives the formula which must be satsified *) and trans_pr_path posi = function | Relative [] -> if posi then Formula.true_ else Formula.false_ - | Relative steps -> List.fold_left - (fun acc x -> if posi then (`Left *+ x) +| acc else (`Left *- x) +| acc) - Formula.false_ (trans_pr_step_l steps) + | Relative steps -> + let dir = match ax_ (List.hd steps) with + | Self -> `Self + | FollowingSibling -> `Right + | _ -> `Left in + List.fold_left + (fun acc x -> if posi then (dir *+ x) +| acc else (dir *- x) +| acc) + Formula.false_ (trans_pr_step_l steps) | AbsoluteDoS steps as x -> print pr_er x; raise Not_core_XPath | Absolute steps as x -> print pr_er x; raise Not_core_XPath - + (* Builds asta for a predicate query and give the formula *) and trans_pr_step_l = function - | [step] -> trans_pr_step [] step + | [step] -> trans_pr_step [] step (Self) (* Self doesn't matter since [] *) | step :: tl -> let list_top = trans_pr_step_l tl in - trans_pr_step list_top step + trans_pr_step list_top step (ax_ (List.hd tl)) | [] -> failwith "Can not happened! 1" (* Add a step on the top of a list of states in a predicate *) - and trans_pr_step list (ax,test,pred) = + and trans_pr_step list (ax,test,pred) ax_next = let form_next = if list = [] then trans_pr pred - else (trans_pr pred) *& - (List.fold_left (fun acc x -> (`Left *+ x) +| acc) - Formula.false_ list) + else form_next_step ax_next list (trans_pr pred) and q = Asta.new_state() and Simple label = test in let tr_next = (q,label, form_next) @@ -126,12 +140,16 @@ let trans query = and form_propa q = function | Child -> `Right *+ q | Descendant -> (`Left *+ q +| `Right *+ q) + | Self -> `Self *+ q + | FollowingSibling -> `Right *+ q | x -> print_axis pr_er x; raise Not_core_XPath (* The same with a selecting state *) and form_propa_selec q q' = function | Child -> `Right *+ q +| `Right *+ q' | Descendant -> (`Left *+ q +| `Right *+ q) +| (`Left *+ q' +| `Right *+ q') + | Self -> `Self *+ q' + | FollowingSibling -> `Right *+ q +| `Right *+ q' | x -> print_axis pr_er x; raise Not_core_XPath in diff --git a/src/formula.ml b/src/formula.ml index 8369571..225440f 100644 --- a/src/formula.ml +++ b/src/formula.ml @@ -15,7 +15,7 @@ INCLUDE "utils.ml" open Format -type move = [ `Left | `Right ] +type move = [ `Left | `Right | `Self ] type 'hcons expr = | False | True | Or of 'hcons * 'hcons @@ -25,7 +25,7 @@ type 'hcons expr = type 'hcons node = { pos : 'hcons expr; mutable neg : 'hcons; - st : StateSet.t * StateSet.t; + st : StateSet.t * StateSet.t * StateSet.t; size: int; (* Todo check if this is needed *) } @@ -73,30 +73,30 @@ let prio f = | Or _ -> 1 (* Begin Lucca Hirschi *) -let rec eval_form ss f = match expr f with +let rec eval_form (q,qf,qn) f = match expr f with | False -> false | True -> true - | And(f1,f2) -> eval_form ss f1 && eval_form ss f2 - | Or(f1,f2) -> eval_form ss f1 || eval_form ss f2 + | And(f1,f2) -> eval_form (q,qf,qn) f1 && eval_form (q,qf,qn) f2 + | Or(f1,f2) -> eval_form (q,qf,qn) f1 || eval_form (q,qf,qn) f2 | Atom(dir, b, s) -> - let set = match dir with |`Left -> fst ss | `Right -> snd ss in + let set = match dir with + |`Left -> qf | `Right -> qn | `Self -> q in if b then StateSet.mem s set else not (StateSet.mem s set) -let rec infer_form ssq ssr f = match expr f with +let rec infer_form sq sqf sqn f = match expr f with | False -> false | True -> true - | And(f1,f2) -> infer_form ssq ssr f1 && infer_form ssq ssr f2 - | Or(f1,f2) -> infer_form ssq ssr f1 || infer_form ssq ssr f2 + | And(f1,f2) -> infer_form sq sqf sqn f1 && infer_form sq sqf sqn f2 + | Or(f1,f2) -> infer_form sq sqf sqn f1 || infer_form sq sqf sqn f2 | Atom(dir, b, s) -> let setq, setr = match dir with - |`Left -> fst ssq, fst ssr - | `Right -> snd ssq, snd ssr in + | `Left -> sqf | `Right -> sqn | `Self -> sq in (* WG: WE SUPPOSE THAT Q^r and Q^q are disjoint ! *) let mem = StateSet.mem s setq || StateSet.mem s setr in if b then mem else not mem (* End *) - + let rec print ?(parent=false) ppf f = if parent then fprintf ppf "("; let _ = match expr f with @@ -117,6 +117,7 @@ let rec print ?(parent=false) ppf f = match dir with | `Left -> Pretty.down_arrow, Pretty.subscript 1 | `Right -> Pretty.down_arrow, Pretty.subscript 2 + | `Self -> Pretty.down_arrow, Pretty.subscript 0 in fprintf fmt "%s%s" a_str d_str; State.print fmt s; @@ -140,26 +141,28 @@ let cons pos neg s1 s2 size1 size2 = pnode,nnode -let empty_pair = StateSet.empty, StateSet.empty -let true_,false_ = cons True False empty_pair empty_pair 0 0 +let empty_triple = StateSet.empty, StateSet.empty, StateSet.empty +let true_,false_ = cons True False empty_triple empty_triple 0 0 let atom_ d p s = let si = StateSet.singleton s in let ss = match d with - | `Left -> si, StateSet.empty - | `Right -> StateSet.empty, si + | `Left -> StateSet.empty, si, StateSet.empty + | `Right -> StateSet.empty, StateSet.empty, si + | `Self -> si, StateSet.empty, StateSet.empty in fst (cons (Atom(d,p,s)) (Atom(d,not p,s)) ss ss 1 1) let not_ f = f.Node.node.neg -let union_pair (l1,r1) (l2, r2) = +let union_triple (s1,l1,r1) (s2,l2, r2) = + StateSet.union s1 s2, StateSet.union l1 l2, StateSet.union r1 r2 let merge_states f1 f2 = let sp = - union_pair (st f1) (st f2) + union_triple (st f1) (st f2) and sn = - union_pair (st (not_ f1)) (st (not_ f2)) + union_triple (st (not_ f1)) (st (not_ f2)) in sp,sn diff --git a/src/formula.mli b/src/formula.mli index 69bdb78..bea2ff5 100644 --- a/src/formula.mli +++ b/src/formula.mli @@ -15,7 +15,7 @@ (** Implementation of hashconsed Boolean formulae *) -type move = [ `Left |`Right ] +type move = [ `Left |`Right | `Self ] (** Direction for automata predicates *) type 'hcons expr = @@ -43,8 +43,8 @@ val equal : t -> t -> bool val expr : t -> t expr (** Equality over formulae *) -val st : t -> StateSet.t * StateSet.t -(** states occuring left and right, positively or negatively *) +val st : t -> StateSet.t * StateSet.t * StateSet.t +(** States occuring self, left and right, positively or negatively *) val compare : t -> t -> int (** Comparison of formulae *) @@ -52,11 +52,11 @@ val compare : t -> t -> int val size : t -> int (** Syntactic size of the formula *) -val eval_form : (StateSet.t * StateSet.t) -> t -> bool -(** [eval_form (sf,sn) F] evaluates the formula [F] on [(sf,sn)] *) +val eval_form : (StateSet.t * StateSet.t * StateSet.t) -> t -> bool +(** [eval_form (s,sf,sn) F] evaluates the formula [F] on [(s,sf,sn)] *) -val infer_form : (StateSet.t * StateSet.t) -> (StateSet.t * StateSet.t) -> t -> bool -(** [eval_form S1 S2 F] infers S1; S2 |- F *) +val infer_form : (StateSet.t * StateSet.t) -> (StateSet.t * StateSet.t) -> (StateSet.t * StateSet.t) -> t -> bool +(** [eval_form S Sf Sn F] infers S; (S1,S2) |- F *) val print : Format.formatter -> t -> unit (** Pretty printer *) diff --git a/src/run.ml b/src/run.ml index 482a749..62ec37a 100644 --- a/src/run.ml +++ b/src/run.ml @@ -25,7 +25,7 @@ module NodeHash = Hashtbl.Make (Node) type t = (StateSet.t*StateSet.t) NodeHash.t (** Map from nodes to query and recognizing states *) -(* Note that we do not consider the nil nodes *) +(* Note that we do not consider nil nodes *) exception Oracle_fail exception Over_max_fail @@ -43,8 +43,8 @@ let rec bu_oracle asta run tree tnode = then () else NodeHash.add run node (map_leaf asta) else - let tfnode = Tree.first_child tree tnode (* first child *) - and tnnode = Tree.next_sibling tree tnode in (* next-sibling *) + let tfnode = Tree.first_child_x tree tnode + and tnnode = Tree.next_sibling tree tnode in let fnode,nnode = (* their preorders *) (Tree.preorder tree tfnode, Tree.preorder tree tnnode) in begin @@ -56,23 +56,29 @@ let rec bu_oracle asta run tree tnode = let (_,qfr),(_,qnr) = q_rec fnode,q_rec nnode (* computed in rec call *) and lab = Tree.tag tree tnode in let _,list_tr = Asta.transitions_lab asta lab in (* only reco. tran.*) - let rec result set = function - | [] -> set + let rec result set flag = function (* add states which satisfy a transition *) + | [] -> set,flag | (q,form) :: tl -> - if Formula.eval_form (qfr,qnr) form (* evaluates the formula *) - then result (StateSet.add q set) tl - else result set tl in - let result_set = result StateSet.empty list_tr in - NodeHash.add run node (StateSet.empty, result_set) + if Formula.eval_form (set,qfr,qnr) form (* evaluates the formula*) + then + if StateSet.mem q set + then result set 0 tl + else result (StateSet.add q set) 1 tl + else result set 0 tl in + let rec fix_point set_i = (* compute the fixed point of states of node *) + let set,flag = result set_i 0 list_tr in + if flag = 0 then set + else fix_point set in + NodeHash.add run node (StateSet.empty, fix_point StateSet.empty) end - + (* Build the over-approx. of the maximal run *) let rec bu_over_max asta run tree tnode = if (Tree.is_leaf tree tnode) (* BU_oracle has already created the map *) then () else - let tfnode = Tree.first_child tree tnode + let tfnode = Tree.first_child_x tree tnode and tnnode = Tree.next_sibling tree tnode in begin bu_over_max asta run tree tfnode; @@ -83,18 +89,20 @@ let rec bu_over_max asta run tree tnode = let q_rec n = try NodeHash.find run n with Not_found -> map_leaf asta in - let (qfq,qfr),(qnq,qnr) = q_rec fnode,q_rec nnode in + let qf,qn = q_rec fnode,q_rec nnode in let lab = Tree.tag tree tnode in - let list_tr,_ = Asta.transitions_lab asta lab in (* only take query st. *) - let rec result set = function - | [] -> set - | (q,form) :: tl -> - if Formula.infer_form (qfq,qnq) (qfr,qnr) form (* infers the formula*) - then result (StateSet.add q set) tl - else result set tl in - let _,resultr = try NodeHash.find run node + let list_tr,_ = Asta.transitions_lab asta lab (* only take query st. *) + and _,resultr = try NodeHash.find run node with _ -> raise Over_max_fail in - let result_set = result StateSet.empty list_tr in + let rec result set flag = function + | [] -> if flag = 0 then set else result set 0 list_tr + | (q,form) :: tl -> + if StateSet.mem q set + then result set 0 tl + else if Formula.infer_form (set,resultr) qf qn form + then result (StateSet.add q set) 1 tl + else result set 0 tl in + let result_set = result StateSet.empty 0 list_tr in (* we keep the old recognizing states set *) NodeHash.replace run node (result_set, resultr) end @@ -107,7 +115,7 @@ let rec tp_max asta run tree tnode = () else let node = Tree.preorder tree tnode - and tfnode = Tree.first_child tree tnode + and tfnode = Tree.first_child_x tree tnode and tnnode = Tree.next_sibling tree tnode in let (fnode,nnode) = (Tree.preorder tree tfnode, Tree.preorder tree tnnode) in @@ -121,23 +129,60 @@ let rec tp_max asta run tree tnode = let q_rec n = try NodeHash.find run n with Not_found -> map_leaf asta in - let (qfq,qfr),(qnq,qnr) = q_rec fnode,q_rec nnode in + let qf,qn = q_rec fnode,q_rec nnode in let lab = Tree.tag tree tnode in let list_tr,_ = Asta.transitions_lab asta lab in (* only take query. *) - let set_node,_ = try NodeHash.find run node - with _ -> raise Max_fail in + let (self_q,self_r) = try NodeHash.find run node + with Not_found -> raise Max_fail in + + (* We must compute again accepting states from self transitions since + previous calls of tp_max may remove them *) + let rec result_q self_q queue = function (* for initializing the queue *) + | [] -> self_q,queue + | (q,form) :: tl -> + if (StateSet.mem q self_q) + then begin + let q_cand,_,_ = Formula.st form in + StateSet.iter (fun x -> Queue.push x queue) q_cand; + result_q (StateSet.add q self_q) queue tl; + end + else result_q self_q queue tl + and result_st_q self_q queue flag = function (*for computing the fixed p*) + | [] -> flag,queue + | form :: tl -> + if Formula.infer_form (self_q,self_r) qf qn form + then begin + let q_cand,_,_ = Formula.st form in + StateSet.iter (fun x -> Queue.push x queue) q_cand; + result_st_q self_q queue 1 tl; + end + else result_st_q self_q queue flag tl in + let rec comp_acc_self self_q_i queue = (* compute the fixed point *) + if Queue.is_empty queue + then self_q_i + else + let q = Queue.pop queue in + let list_q,_ = Asta.transitions_st_lab asta q lab in + let flag,queue = result_st_q self_q_i queue 0 list_q in + let self_q = if flag = 1 then StateSet.add q self_q_i else self_q_i in + comp_acc_self self_q queue in + + let self,queue_init = result_q self_q (Queue.create()) list_tr in + let self_q = comp_acc_self self_q queue_init in + NodeHash.replace run node (self_q,self_r); + (* From now, the correct set of states is mapped to node! *) let rec result = function | [] -> [] | (q,form) :: tl -> - if (Formula.infer_form (qfq,qnq) (qfr,qnr) form) && - (StateSet.mem q set_node) (* infers & trans. can start here *) + if (StateSet.mem q self) && (* infers & trans. can start here *) + (Formula.infer_form (self_q,self_r) qf qn form) then form :: (result tl) - else result tl in + else result tl in let list_form = result list_tr in (* tran. candidates *) (* compute states occuring in transition candidates *) let rec add_st (ql,qr) = function | [] -> ql,qr - | f :: tl -> let sql,sqr = Formula.st f in + | f :: tl -> let sqs,sql,sqr = Formula.st f in let ql' = StateSet.union sql ql and qr' = StateSet.union sqr qr in add_st (ql',qr') tl in @@ -147,12 +192,13 @@ let rec tp_max asta run tree tnode = and qnq,qnr = try NodeHash.find run nnode with | _ -> map_leaf asta in begin - if tfnode == Tree.nil + if tfnode == Tree.nil || Tree.is_attribute tree tnode then () else NodeHash.replace run fnode (StateSet.inter qfq ql,qfr); - if tnnode == Tree.nil + if tnnode == Tree.nil || Tree.is_attribute tree tnode then () else NodeHash.replace run nnode (StateSet.inter qnq qr,qnr); + (* indeed we delete all states from self transitions! *) tp_max asta run tree tfnode; tp_max asta run tree tnnode; end; @@ -178,7 +224,7 @@ let selected_nodes tree asta = NodeHash.fold (fun key set acc -> if not(StateSet.is_empty - (StateSet.inter (fst set) (Asta.selec_states asta))) + (StateSet.inter (fst set) (Asta.selec_states asta))) then key :: acc else acc) run [] diff --git a/src/tree.ml b/src/tree.ml index 2b0fa4e..434d195 100644 --- a/src/tree.ml +++ b/src/tree.ml @@ -261,10 +261,16 @@ let rec print_xml out tree_ node = let root t = t.root let first_child _ n = n.first_child +let first_child_x _ n = + if n.first_child.tag == QName.attribute_map + then n.first_child.next_sibling + else n.first_child let next_sibling _ n = n.next_sibling let parent _ n = n.parent (* Begin Lucca Hirschi *) -let is_leaf t n = (first_child t n == nil) && (next_sibling t n == nil) +let is_leaf t n = (not (n.tag == QName.attribute_map)) && + (first_child t n == nil) && (next_sibling t n == nil) +let is_attribute t n = n.tag == QName.attribute_map (* End *) let tag _ n = n.tag let data _ n = n.data @@ -287,7 +293,8 @@ let rec print_xml_preorder out tree_ node = let fchild = if node.first_child.tag == QName.attribute_map then let () = - print_attributes out tree_ node.first_child.first_child + let ffn = node.first_child.first_child in + print_attributes out tree_ ffn; in node.first_child.next_sibling else @@ -303,3 +310,6 @@ let rec print_xml_preorder out tree_ node = end in print_xml_preorder out tree_ node.next_sibling + +let debug_node fmt t n = + Parser.debug_node fmt n diff --git a/src/tree.mli b/src/tree.mli index c75fd26..b64b0ff 100644 --- a/src/tree.mli +++ b/src/tree.mli @@ -49,6 +49,12 @@ val first_child : t -> node -> node Returns [nil] if [n] is a leaf. Returns [nil] if [n == nil]. *) +val first_child_x : t -> node -> node +(** [first_child t n] returns the first child which is not an attribute + of node [n] in tree [t]. + Returns [nil] if [n] is a leaf. Returns [nil] if [n == nil]. +*) + val next_sibling : t -> node -> node (** [next_sibling t n] returns the next_sibling of node [n] in tree [t]. Returns [nil] if [n] is the last child of a node. @@ -62,7 +68,10 @@ val parent : t -> node -> node *) val is_leaf : t -> node -> bool -(** Return true if the node is a *) +(** Return true if the node is a leaf or an attribute *) + +val is_attribute : t -> node -> bool +(** Return true if the node is an attribute *) val tag : t -> node -> QName.t (** Returns the label of a given node *) @@ -81,3 +90,6 @@ val preorder : t -> node -> int val print_xml_preorder : out_channel -> t -> node -> unit (** Outputs the tree with IDs for nodes as an XML document on the given output_channel *) + +val debug_node : Format.formatter -> t -> node -> unit +(** DEBUG *) diff --git a/tests/docs/XPath-FT.xml b/tests/docs/XPath-FT.xml index 90aef04..bd46991 100644 --- a/tests/docs/XPath-FT.xml +++ b/tests/docs/XPath-FT.xml @@ -1 +1,40 @@ -clergywomandecadentgentilityhappy-go-lucky manjigsawkerchiefThe letter L is followed by the letter:which is followed by the letter:ovenware

plentiful

quarrelsome
sagetatteredvoluptuarywriggle
yawnzuzzurellone
+ + +clergywoman +decadent + + + +gentility +happy-go-lucky man + + +jigsaw +kerchief + + + +The letter L is followed by the letter: + +which is followed by the letter: + +ovenware +

plentiful

+
+ +quarrelsome +
+ +sage +tattered + + +voluptuary +wriggle + +
+ +yawn +zuzzurellone + +
diff --git a/tests/queries/XPath-FT.queries b/tests/queries/XPath-FT.queries index bf29a0d..de956e9 100644 --- a/tests/queries/XPath-FT.queries +++ b/tests/queries/XPath-FT.queries @@ -1,4 +1,4 @@ -/descendant::L +/descendant::L/child::* /descendant::L/descendant::* /descendant::L/following-sibling::* /descendant::L/self::*