使用单引号和双引号编码XPath表达式

XPath(v1)无法编码表达式。

如果您只有单个OR双引号,那么您可以使用诸如的单词

//review[@name="Bob's Pizza"] //review[@name='"Pizza" Pam'] 

但是如果你有两个例如[弗雷德的“Fancy Pizza”]那么你必须在XPath(C ++)中使用类似Escaping Strings的东西来生成

 //review[@name=Concat("Fred's ",'"Fancy Pizza"')] 

任何人都有c#函数来执行此操作?

一些链接很接近

  • 使用MVP.XML库和XPathVariable (一个非常好的解决方案,但对我的需求有点重量级)。
  • 不编码“和”存在的位置
  • 为Concat操作添加的参数多于必要的参数,例如返回//评论[@ name = concat(’Fred’,”’,’s’,’“’,’Fancy Pizza’,”’,”) ]

编辑:一些答案建议逃避’与' 和“with "但是虽然这是有道理的但是它不起作用;使用XML片段尝试它:

  

和xpath

 //review[@name='Bob's Pizza'] 

哇,你们都肯定会让这个变得复杂。 为什么不这样做呢?

 public static string XpathExpression(string value) { if (!value.Contains("'")) return '\'' + value + '\''; else if (!value.Contains("\"")) return '"' + value + '"'; else return "concat('" + value.Replace("'", "',\"'\",'") + "')"; } 

.NET小提琴和测试

虽然它肯定不会在所有情况下都起作用,但这是一种回避问题的方法:

 doc.DocumentElement.SetAttribute("searchName", name); XmlNode n = doc.SelectNodes("//review[@name=/*/@searchName]"); 

我需要这个,所以我为C#创建了这个解决方案。

  ///  /// Returns a valid XPath statement to use for searching attribute values regardless of 's or "s ///  /// Attribute value to parse /// Parsed attribute value in concat() if needed public static string GetXpathStringForAttributeValue(string attributeValue) { bool hasApos = attributeValue.Contains("'"); bool hasQuote = attributeValue.Contains("\""); if (!hasApos) { return "'" + attributeValue + "'"; } if (!hasQuote) { return "\"" + attributeValue + "\""; } StringBuilder result = new StringBuilder("concat("); StringBuilder currentArgument = new StringBuilder(); for (int pos = 0; pos < attributeValue.Length; pos++) { switch (attributeValue[pos]) { case '\'': result.Append('\"'); result.Append(currentArgument.ToString()); result.Append("'\","); currentArgument.Length = 0; break; case '\"': result.Append('\''); result.Append(currentArgument.ToString()); result.Append("\"\',"); currentArgument.Length = 0; break; default: currentArgument.Append(attributeValue[pos]); break; } } if (currentArgument.Length == 0) { result[result.Length - 1] = ')'; } else { result.Append("'"); result.Append(currentArgument.ToString()); result.Append("')"); } return result.ToString(); } 

这就是我想出来的

 public static string EncaseXpathString(string input) { // If we don't have any " then encase string in " if (!input.Contains("\"")) return String.Format("\"{0}\"", input); // If we have some " but no ' then encase in ' if (!input.Contains("'")) return String.Format("'{0}'", input); // If we get here we have both " and ' in the string so must use Concat StringBuilder sb = new StringBuilder("concat("); // Going to look for " as they are LESS likely than ' in our data so will minimise // number of arguments to concat. int lastPos = 0; int nextPos = input.IndexOf("\""); while (nextPos != -1) { // If this is not the first time through the loop then seperate arguments with , if (lastPos != 0) sb.Append(","); sb.AppendFormat("\"{0}\",'\"'", input.Substring(lastPos, nextPos - lastPos)); lastPos = ++nextPos; // Find next occurance nextPos = input.IndexOf("\"", lastPos); } sb.Append(")"); return sb.ToString(); } 

叫做类似的东西

 XmlNode node = doc.SelectSingleNode("//review[@name=" + EncaseXpathString("Fred's \"Fancy Pizza\"" + "]") 

所以我们得到以下结果

 EncaseXpathString("Pizza Shed") == "'Pizza Shed'"; EncaseXpathString("Bob's pizza") == "\"Bob's Pizza\""; EncaseXpathString("\"Pizza\" Pam" == "'\"Pizza\" Pam'"; EncaseXpathString("Fred's \"Fancy Pizza\"") == "concat(\"Fred's \",'\"',\"Fancy Pizza\",'\"')"; 

所以它只在必要时才使用concat(字符串中的“和”)

最后的结果显示concat操作并不尽可能短(请参阅问题),但它足够接近并且任何更优化都会非常复杂,因为您必须寻找匹配的“或”对。

到目前为止,我遇到了所有解决方案的问题。 一个有额外的文本部分(例如’“’或”’),它打破了你正在寻找的东西。一个删除了最后一个引用/ dblquote之后的所有文本,它也会中断。

这是一个愚蠢的vb开发人员的愚蠢而快速的解决方案:

 Function ParseXpathString(ByVal input As String) As String input = Replace(input, "'", Chr(1)) input = Replace(input, """", Chr(2)) input = Replace(input, Chr(1), "',""'"",'") input = Replace(input, Chr(2), "','""','") input = "concat('','" + input + "')" Return input End Function 

用法(与前面的例子相同):

 x.SelectNodes("/path[@attr=" & ParseXpathString(attrvalue) & "]") 

我需要在XSLT本身中执行此操作,因此基于此页面上的答案提出以下内容:

    " '  '' ""  concat(     , "'",      )    

另一种变化……我的concat()部分有点懒,但至少它使用了整个值。

  ///  /// Returns an XPath string literal to use for searching attribute values (wraped in apostrophes, quotes, or as a concat function). ///  /// Attribute value to encode and wrap. public static string CreateXpathLiteral(string attributeValue) { if (!attributeValue.Contains("\"")) { // if we don't have any quotes, then wrap string in quotes... return string.Format("\"{0}\"", attributeValue); } else if (!attributeValue.Contains("'")) { // if we have some quotes, but no apostrophes, then wrap in apostrophes... return string.Format("'{0}'", attributeValue); } else { // must use concat so the literal in the XPath will find a match... return string.Format("concat(\"{0}\")", attributeValue.Replace("\"", "\",'\"',\"")); } } 

加入这个有趣的事物

 public string XPathLiteral(string text) { const string APOS = "'"; const string QUOTE = @""""; int pos = 0; int posApos; int posQuote; posQuote = text.IndexOf(QUOTE, pos); if (posQuote < 0) { return QUOTE + text + QUOTE; }//if posApos = text.IndexOf(APOS, pos); if (posApos < 0) { return APOS + text + APOS; }//if bool containsApos = posApos < posQuote; StringBuilder sb = new StringBuilder("concat(", text.Length * 2); bool loop = true; bool comma = false; while (loop) { if (posApos < 0) { posApos = text.Length; loop = false; }//if if (posQuote < 0) { posQuote = text.Length; loop = false; }//if if (comma) { sb.Append(","); } else { comma = true; }//if if (containsApos) { sb.Append(QUOTE); sb.Append(text.Substring(pos, posQuote - pos)); sb.Append(QUOTE); pos = posQuote; if (loop) posApos = text.IndexOf(APOS, pos + 1); } else { sb.Append(APOS); sb.Append(text.Substring(pos, posApos - pos)); sb.Append(APOS); pos = posApos; if (loop) posQuote = text.IndexOf(QUOTE, pos + 1); }//if // Toggle containsApos = !containsApos; }//while sb.Append(")"); return sb.ToString(); }//method 

url: http : //vaibhavgaikwad.wordpress.com/2007/10/04/handling-apostrophe-single-quote-in-xpath-expressions-in-net/

引用:

  public static string GetXPathString(string input) { string[] fragments = input.Split(new char[] { '\” }); string result = “”; result += “concat(””; for (int i = 0; i < fragments.Length; i++) { result += “, '” + fragments[i] + “'”; if (i < fragments.Length - 1) { result += “, \”'\”"; } } result += “)”; return result; } 

以下是修改上述代码以便使用我们的新函数的方法://记得在=和之后删除单引号

 XmlNode n = doc.SelectSingleNode(“/root/emp[@lname=" + GetXPathString(ln) + "]“); 

或者只是像之前的post那样建议。 使用'和'替换'和'一个简单的function。