module XTemplate::XPath

Constants

AnyNode
AnyNode0
AnyNode2
CurrentNode
ParentNode
PathIfNot
PathSeparator
PathUnion
RootNode
TextNode
VALUE_BY_PATH1
VALUE_BY_PATH2_1
VALUE_BY_PATH2_2
VALUE_BY_PATH3

Public Class Methods

use_default_xpath() click to toggle source
# File lib/xtemplate/xpath.rb, line 1012
def use_default_xpath()
  XPath.module_eval(VALUE_BY_PATH1 + VALUE_BY_PATH2_1 + VALUE_BY_PATH3)
end
use_simple_xpath() click to toggle source
# File lib/xtemplate/xpath.rb, line 1016
def use_simple_xpath()
  XPath.module_eval(VALUE_BY_PATH1 + VALUE_BY_PATH2_2 + VALUE_BY_PATH3)
end

Public Instance Methods

args_split(args) click to toggle source

also implemented in xt.c

# File lib/xtemplate/xpath.rb, line 639
def args_split(args)
  args = unsanitize(args)
  i = 0
  l = false
  s = 0
  escape = false
  inref  = false
  ids = []
  args.each_byte{|c|
    case c
    when ', "
      if( escape )
        escape = false
      else
        if( l )
          l = false
        else
          l = true
        end
      end
    when \           escape = true
    when ,
      if( !l )
        ids.push(args[s..i].chop)
        s = i + 1
      end
    end
    i += 1
  }
  ids.push(args[s..i])
  ids.collect{|s| s.strip.gsub(/(\A['"])|(["']\z)/,'') }.reject{|s| s.empty? }
end
cond_split(path) click to toggle source

also implemented in xt.c

# File lib/xtemplate/xpath.rb, line 674
def cond_split(path)
  i = 0
  l = 0
  s = 0
  xs = []
  path.each_byte{|c|
    case c
    when {, [
      if( l == 0 )
        case i
        when 0
          xs.push("")
        when s
          # do nothing
        else
          xs.push(path[s..(i-1)])
        end
        s = i
      end
      l += 1
    when }, ]
      l -= 1
      if( l == 0 )
        xs.push(path[s..i])
        s = i + 1
      end
    end
    i += 1
  }
  unless( s == i )
    xs.push(path[s..i])
  end
  xs
end
eval_action(act, val, plugin) click to toggle source
# File lib/xtemplate/xpath.rb, line 1127
def eval_action(act, val, plugin)
  newval = nil
  act.strip!
  if( act.include?(";") )
    newval = val
    act.split(";").each{|a|
      newval = eval_action(a.strip, newval, plugin)
    }
    return newval
  end
  if( act =~ /^([^\(\)]+)\(([^\(\)]*)\)$/ )
    func = $1.strip
    args = args_split($2)
    newval = plugin.__send__(func,val,*args)
  else
    case val
    when Array
      newval = val.collect{|x| {act => x} }
    else
      newval = {act => val}
    end
  end
  newval
end
eval_condition(expr, val, plugin) click to toggle source
# File lib/xtemplate/xpath.rb, line 1084
def eval_condition(expr, val, plugin)
  if( expr =~ /\s+or\s+/ )
    expr.split(/\s+or\s+/).any?{|x| eval_condition(x.strip,val,plugin) }
  elsif( expr =~ /\s+and\s+/ )
    expr.split(/\s+and\s+/).all?{|x| eval_condition(x.strip,val,plugin) }
  elsif( expr =~ /^not\s+(.+)$/ )
    ! eval_condition($1.strip,val,plugin)
  else
    case expr
    when /^([^!=<>~\s\(\)]+(\([^!=<>~\s\(\)]*\))?)\s*(=|!=|<|>|<=|>=|=~|!~|&lt;=?|&gt;=?)\s*([^!=<>~\s\(\)]+(\([^!=<>~\s\(\)]*\))?)$/
      lhs = eval_expr($1.strip,val,plugin)
      op  = $3
      rhs = eval_expr($4.strip,val,plugin)
      unless( lhs.nil? || rhs.nil? )
        case op
        when '='
          (lhs == rhs)
        when '&lt;', '<'
          (lhs < rhs)
        when '&lt;=', '<='
          (lhs <= rhs)
        when '&gt;', '>'
          (lhs > rhs)
        when '&gt;=', '>='
          (lhs >= rhs)
        when '=~'
          (lhs =~ rhs)
        when '!~'
          (lhs !~ rhs)
        else
          raise(NotImplementedError, "'#{op}'")
        end
      else
        false
      end
    when /^([^=<>~]+)$/
      eval_expr($1.strip,val,plugin)
    else
      nil
    end
  end # end of 'else'
end
eval_expr(expr, val, plugin) click to toggle source
# File lib/xtemplate/xpath.rb, line 1023
def eval_expr(expr, val, plugin)
  case expr
  when "text()"
    if( val.is_a?(Hash) && val[TextNode] && val.size == 1 )
      val[TextNode]
    else
      val
    end
  when "size()"
    case val
    when Array
      val.size
    when nil
      0
    else
      1
    end
  when /int\((.+)\)/
    eval_expr($1,val,plugin).to_i
  when /float\((.+)\)/
    eval_expr($1,val,plugin).to_f
  when /^(-?\d+)$/
    $1.to_i
  when /^(-?\d+)\.(\d+)$/
    $1.to_f
  when /^('|"|&quot;|&apos;)(.+)('|"|&quot;|&apos;)$/
    str = $2
    str.gsub(/\./){|m| $1}
  when /^%q\((.+)\)$/
    str = $1
    str.gsub(/\./){|m| $1}
  when /^%r\((.+)\)$/, %r{/(.+)/}
    str = $1
    str.gsub!(/\./){|m| $1}
    Regexp.new(str)
  when 'nil'
    nil
  else
    path_split(expr).each{|path|
      case val
      when Hash
        val = val[path]
        if( val.is_a?(Hash) && val[TextNode] && val.size == 1 )
          val = val[TextNode]
        end
      when Array
        val = val.collect{|v|
          eval_expr(path, v, plugin)
        }.flatten.reject{|v| v.nil?}
        if( val.size == 0 )
          val = nil
        end
      else
        val = nil
        break
      end
    }
    val
  end
end
normalize(val) click to toggle source
# File lib/xtemplate/xpath.rb, line 772
def normalize(val)
  case val
  when Hash
    if( val[TextNode] && val.size == 1 )
      val = val[TextNode]
    end
  when XArray
    val = val.reject{|v| v.is_a?(String) && (v =~ /\A\s*\z/) }
    if( val.size > 1 )
      catch(:break){
        h = {}
        node_p = false
        val.each{|v|
          case v
          when Hash
            v.each{|k,x|
              if( h[k] )
                throw(:break)
              else
                h[k] = x
                unless( k && (k[0] == @) )
                  node_p = true
                end
              end
            }
          else
            if( h[TextNode] )
              throw(:break)
            else
              h[TextNode] = v
            end
          end
        }
        if( h[TextNode] )
          if( h.size == 1 )
            h = h[TextNode]
          else
            if( node_p )
              throw(:break)
            end
          end
        end
        val.clear
        val.push(h)
      }
    end
  when Array
    val.reject!{|x|x.nil?}
  end
  val
end
path_split(path) click to toggle source

also implemented in xt.c

# File lib/xtemplate/xpath.rb, line 612
def path_split(path)
  i = 0
  l = 0
  s = 0
  ids = []
  path.each_byte{|c|
    case c
    when {, [
      l += 1
    when }, ]
      l -= 1
    when /
      if( l == 0 )
        ids.push(path[s..i].chop)
        s = i + 1
      end
    end
    i += 1
  }
  ids.push(path[s..i])
  if( path[0] == / )
    ids[0] = RootNode
  end
  ids
end
value_by_path2(path, data, pdata, rdata, plugin) click to toggle source

Returns an empty array instead of 'nil' to eliminate a tag.

# File lib/xtemplate/xpath.rb, line 725
def value_by_path2(path, data, pdata, rdata, plugin)
  if( path.is_a?(String) )
    if( path =~ /([\?\|])/ )
      case $1[0]
      when |
        paths = path.split(PathUnion)
        return paths.collect{|path|
          path.strip!
          value_by_path2(path, data, pdata, rdata, plugin)
        }.flatten
      when ?
        paths = path.split(PathIfNot)
        for path in paths
          path.strip!
          vals = value_by_path2(path, data, pdata, rdata, plugin)
          if( vals.nil? || vals.empty? )
            next
          end
          break
        end
        return vals
      end
    end
    ids = path_split(path)
  else
    ids = path.dup
  end

  x = value_by_path(ids, data, pdata, rdata, plugin)

  if( x )
    case x
    when Array
      x.reject!{|e|e.nil?}
      if( x.size == 1 )
        x[0]
      else
        x
      end
    else
      x
    end
  else
    []
  end
end
value_depth(val) click to toggle source
# File lib/xtemplate/xpath.rb, line 544
def value_depth(val)
  case val
  when Hash
    max = 0
    val.each{|key,val|
      if( key == ParentNode )
        next
      end
      if( (x = value_depth(val)) > max )
        max = x
      end
    }
    max + 1
  when Array
    max = 0
    val.each{|val|
      if( (x = value_depth(val)) > max )
        max = x
      end
    }
    max
  else
    0
  end
end
value_inspect(val) click to toggle source
# File lib/xtemplate/xpath.rb, line 529
def value_inspect(val)
  case val
  when Hash
    val = val.dup
    val.delete(ParentNode)
    "{" + val.collect{|k,v| "#{k.inspect}=>#{value_inspect(v)}" }.join(", ") + "}"
  when Array
    "#{val.class}[" + val.collect{|v| value_inspect(v)}.join(", ") + "]"
  when SanitizedString
    val.to_s.inspect
  else
    val.inspect
  end
end
value_p(val) click to toggle source
# File lib/xtemplate/xpath.rb, line 570
def value_p(val)
  puts(value_inspect(val))
end
value_to_xml(val, parent) click to toggle source
# File lib/xtemplate/xpath.rb, line 574
def value_to_xml(val, parent)
  case val
  when Hash
    val.each{|k,v|
      case k
      when ParentNode
        # do nothing
      when TextNode
        parent.add_child(v)
      when /^@(.+)/
        parent.add_attr($1)
        parent.add_attrval(v)
      else
        node = XNode.new(k)
        value_to_xml(v,node)
        parent.add_child(node)
      end
    }
  when Array
    val = val.collect{|v|
      case v
      when Hash, Array
        v
      else
        {TextNode => v}
      end
    }
    val.each{|v|
      value_to_xml(v,parent)
    }
  when nil
    nil
  else
    parent.add_child(val)
  end
end
xpath(path, data, plugin=nil) click to toggle source
# File lib/xtemplate/xpath.rb, line 709
def xpath(path, data, plugin=nil)
  plugin ||= Action.new
  x = value_by_path2(path, data, nil, data, plugin)
  if( x.nil? )
    nil
  else
    case x
    when Array
      x
    else
      [x]
    end
  end
end