If you used an engine that only supports XPath 1.0 paths, you can consider this value as a template whose grammar is:
start : parts EOI parts : part parts | part : string_literal | variable | other
The following is the XPath from the XPath template.
sub text_to_xpath_lit { my ($s) = @_; return qq{"$s"} if $s !~ /"/; return qq{'$s'} if $s !~ /'/; $s =~ s/"/", '"', "/g; return qq{concat("$s")}; } my $NCNameStartChar_class = '_A-Za-z\xC0-\xD6\xD8-\xF6\xF8-\x{2FF}\x{370}-\x{37D}\x{37F}-\x{1FFF}\x{200C}-\x{200D}\x{2070}-\x{218F}\x{2C00}-\x{2FEF}\x{3001}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFFD}\x{10000}-\x{EFFFF}'; my $NCNameChar_class = $NCNameStartChar_class . '\-.0-9\xB7\x{300}-\x{36F}\x{203F}-\x{2040}'; my $NCName_pat = "[$NCNameStartChar_class][$NCNameChar_class]*+";
my $xpath = ''; for ($xpath_template) { while (1) { if (/\G ( [^'"\$]++ ) /xgc) { $xpath .= $1; } elsif (/\G (?=['"]) /xgc) { /\G ( ' [^\\']*+ ' | " [^\\"]*+ " ) /sxgc or die("Unmatched quote\n"); $xpath .= $1; } elsif (/\G \$ /xgc) { /\G (?: ( $NCName_pat ) : )?+ ( $NCName_pat ) /xgc or die("Unexpected '\$'\n"); my ($prefix, $var_name) = ($1, $2); my $ns = $ns_map{$prefix} or die("Undefined prefix '$prefix'\n"); $xpath .= text_to_xpath_lit(var_lookup($ns, $var_name)); } elsif (/\G \z /xgc) { last; } } }
var_lookup example:
sub var_lookup { my ($ns, $var_name) = @_; $var_name = "{$ns}$var_name" if defined($ns); my $val = $params{$var_name}; if (!defined($val)) { warn("Unknown variable \"$var_name\"\n"); $val = ''; } return $val; }
Unverified.
source share