问题描述
我使用以下 XPATH 查询
来列出站点下的对象.ListObject[@Title='SomeValue']
.SomeValue 是动态的.只要 SomeValue 没有撇号 ('),此查询就有效.也尝试使用转义序列.没用.
I use the following XPATH Query
to list the object under a site. ListObject[@Title='SomeValue']
. SomeValue is dynamic. This query works as long as SomeValue does not have an apostrophe ('). Tried using escape sequence also. Didn't work.
我做错了什么?
推荐答案
这很难做到.
看看XPath Recommendation,你会看到它定义了一个文字如:
Take a look at the XPath Recommendation, and you'll see that it defines a literal as:
Literal ::= '"' [^"]* '"'
| "'" [^']* "'"
也就是说,XPath 表达式中的字符串文字可以包含撇号或双引号,但不能同时包含两者.
Which is to say, string literals in XPath expressions can contain apostrophes or double quotes but not both.
你不能使用转义来解决这个问题.像这样的文字:
You can't use escaping to get around this. A literal like this:
'Some'Value'
将匹配此 XML 文本:
will match this XML text:
Some'Value
这确实意味着可能会有一段 XML 文本无法生成 XPath 文字来匹配,例如:
This does mean that it's possible for there to be a piece of XML text that you can't generate an XPath literal to match, e.g.:
<elm att=""&apos"/>
但这并不意味着用 XPath 匹配该文本是不可能的,它只是很棘手.在您尝试匹配的值同时包含单引号和双引号的任何情况下,您都可以构造一个使用 concat
来生成要匹配的文本的表达式:
But that doesn't mean it's impossible to match that text with XPath, it's just tricky. In any case where the value you're trying to match contains both single and double quotes, you can construct an expression that uses concat
to produce the text that it's going to match:
elm[@att=concat('"', "'")]
这让我们想到了这个,这比我想要的要复杂得多:
So that leads us to this, which is a lot more complicated than I'd like it to be:
/// <summary>
/// Produce an XPath literal equal to the value if possible; if not, produce
/// an XPath expression that will match the value.
///
/// Note that this function will produce very long XPath expressions if a value
/// contains a long run of double quotes.
/// </summary>
/// <param name="value">The value to match.</param>
/// <returns>If the value contains only single or double quotes, an XPath
/// literal equal to the value. If it contains both, an XPath expression,
/// using concat(), that evaluates to the value.</returns>
static string XPathLiteral(string value)
{
// if the value contains only single or double quotes, construct
// an XPath literal
if (!value.Contains("""))
{
return """ + value + """;
}
if (!value.Contains("'"))
{
return "'" + value + "'";
}
// if the value contains both single and double quotes, construct an
// expression that concatenates all non-double-quote substrings with
// the quotes, e.g.:
//
// concat("foo", '"', "bar")
StringBuilder sb = new StringBuilder();
sb.Append("concat(");
string[] substrings = value.Split('"');
for (int i = 0; i < substrings.Length; i++ )
{
bool needComma = (i>0);
if (substrings[i] != "")
{
if (i > 0)
{
sb.Append(", ");
}
sb.Append(""");
sb.Append(substrings[i]);
sb.Append(""");
needComma = true;
}
if (i < substrings.Length - 1)
{
if (needComma)
{
sb.Append(", ");
}
sb.Append("'"'");
}
}
sb.Append(")");
return sb.ToString();
}
是的,我用所有边缘情况对其进行了测试.这就是为什么逻辑如此复杂:
And yes, I tested it with all the edge cases. That's why the logic is so stupidly complex:
foreach (string s in new[]
{
"foo", // no quotes
""foo", // double quotes only
"'foo", // single quotes only
"'foo"bar", // both; double quotes in mid-string
"'foo"bar"baz", // multiple double quotes in mid-string
"'foo"", // string ends with double quotes
"'foo""", // string ends with run of double quotes
""'foo", // string begins with double quotes
"""'foo", // string begins with run of double quotes
"'foo""bar" // run of double quotes in mid-string
})
{
Console.Write(s);
Console.Write(" = ");
Console.WriteLine(XPathLiteral(s));
XmlElement elm = d.CreateElement("test");
d.DocumentElement.AppendChild(elm);
elm.SetAttribute("value", s);
string xpath = "/root/test[@value = " + XPathLiteral(s) + "]";
if (d.SelectSingleNode(xpath) == elm)
{
Console.WriteLine("OK");
}
else
{
Console.WriteLine("Should have found a match for {0}, and didn't.", s);
}
}
Console.ReadKey();
}
这篇关于XPath 查询中的撇号 (')的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!