Merge branch 'lucca-tests-bench' into lucca-extentions lucca-extentions Core+FS+Self_tested
authorLucca Hirschi <lucca.hirschi@gmail.com>
Tue, 17 Jul 2012 12:57:28 +0000 (14:57 +0200)
committerLucca Hirschi <lucca.hirschi@gmail.com>
Tue, 17 Jul 2012 12:57:28 +0000 (14:57 +0200)
12 files changed:
correct_test
run_tests
src/asta.ml
src/asta.mli
src/compil.ml
src/formula.ml
src/formula.mli
src/run.ml
src/tree.ml
src/tree.mli
tests/docs/XPath-FT.xml
tests/queries/XPath-FT.queries

index d28ee73..ec62b8a 100755 (executable)
@@ -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
index 4a26469..6ee6c55 100755 (executable)
--- 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
index d866005..965486a 100644 (file)
@@ -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;
index 7bbf13d..3fd9886 100644 (file)
@@ -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 *)
 
index 574485e..b15b069 100644 (file)
@@ -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
index 8369571..225440f 100644 (file)
@@ -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
 
index 69bdb78..bea2ff5 100644 (file)
@@ -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 *)
index 482a749..62ec37a 100644 (file)
@@ -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 []
index 2b0fa4e..434d195 100644 (file)
@@ -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
index c75fd26..b64b0ff 100644 (file)
@@ -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 *)
index 90aef04..bd46991 100644 (file)
@@ -1 +1,40 @@
-<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE A SYSTEM "alphabet.dtd"><A id="n1" pre="1" post="26" xml:lang="en"><B id="n2" pre="2" post="3"><C id="n3" pre="3" post="1">clergywoman</C><D id="n4" pre="4" post="2">decadent</D></B><E id="n5" pre="5" post="22"><F id="n6" pre="6" post="6"><G id="n7" pre="7" post="4">gentility</G><H id="n8" pre="8" post="5" idrefs="n17 n26">happy-go-lucky man</H></F><I id="n9" pre="9" post="9"><J id="n10" pre="10" post="7">jigsaw</J><K id="n11" pre="11" post="8">kerchief</K></I><L id="n12" pre="12" post="15"><!--L is the twelve-th letter of the English alphabet-->The letter L is followed by the letter:<M id="n13" pre="13" post="10"/>which is followed by the letter:<N id="n14" pre="14" post="13"><O id="n15" pre="15" post="11">ovenware</O><P id="n16" pre="16" post="12">plentiful</P></N><?myPI value="XPath is nice"?><Q id="n17" pre="17" post="14" idrefs="n8 n26">quarrelsome</Q></L><R id="n18" pre="18" post="18"><S id="n19" pre="19" post="16">sage</S><T id="n20" pre="20" post="17">tattered</T></R><U id="n21" pre="21" post="21"><V id="n22" pre="22" post="19">voluptuary</V><W id="n23" pre="23" post="20">wriggle</W></U></E><X id="n24" pre="24" post="25"><Y id="n25" pre="25" post="23">yawn</Y><Z id="n26" pre="26" post="24" idrefs="n8 n17" xml:lang="it">zuzzurellone</Z></X></A>
+<A id="n1" pre="1" post="26" xml:lang="en">
+<B id="n2" pre="2" post="3">
+<C id="n3" pre="3" post="1">clergywoman</C>
+<D id="n4" pre="4" post="2">decadent</D>
+</B>
+<E id="n5" pre="5" post="22">
+<F id="n6" pre="6" post="6">
+<G id="n7" pre="7" post="4">gentility</G>
+<H id="n8" pre="8" post="5" idrefs="n17 n26">happy-go-lucky man</H>
+</F>
+<I id="n9" pre="9" post="9">
+<J id="n10" pre="10" post="7">jigsaw</J>
+<K id="n11" pre="11" post="8">kerchief</K>
+</I>
+<L id="n12" pre="12" post="15">
+<!-- L is the twelve-th letter of the English alphabet -->
+The letter L is followed by the letter:
+<M id="n13" pre="13" post="10"/>
+which is followed by the letter:
+<N id="n14" pre="14" post="13">
+<O id="n15" pre="15" post="11">ovenware</O>
+<P id="n16" pre="16" post="12">plentiful</P>
+</N>
+<?myPI value="XPath is nice"?>
+<Q id="n17" pre="17" post="14" idrefs="n8 n26">quarrelsome</Q>
+</L>
+<R id="n18" pre="18" post="18">
+<S id="n19" pre="19" post="16">sage</S>
+<T id="n20" pre="20" post="17">tattered</T>
+</R>
+<U id="n21" pre="21" post="21">
+<V id="n22" pre="22" post="19">voluptuary</V>
+<W id="n23" pre="23" post="20">wriggle</W>
+</U>
+</E>
+<X id="n24" pre="24" post="25">
+<Y id="n25" pre="25" post="23">yawn</Y>
+<Z id="n26" pre="26" post="24" idrefs="n8 n17" xml:lang="it">zuzzurellone</Z>
+</X>
+</A>
index bf29a0d..de956e9 100644 (file)
@@ -1,4 +1,4 @@
-/descendant::L
+/descendant::L/child::*
 /descendant::L/descendant::* 
 /descendant::L/following-sibling::*
 /descendant::L/self::*