C'est étonnamment difficile à faire.
Jetez un coup d'œil à la Recommandation XPath et vous verrez qu'il définit un littéral comme suit :
Literal ::= '"' [^"]* '"'
| "'" [^']* "'"
En d'autres termes, les chaînes de caractères dans les expressions XPath peuvent contenir des apostrophes ou des guillemets doubles, mais pas les deux.
Vous ne pouvez pas utiliser l'échappement pour contourner ce problème. Un littéral comme celui-ci :
'Some'Value'
correspondra à ce texte XML :
Some'Value
Cela signifie qu'il est possible qu'il y ait un morceau de texte XML pour lequel vous ne pouvez pas générer un littéral XPath, par exemple :
<elm att=""&apos"/>
Mais cela ne signifie pas qu'il est impossible de faire correspondre ce texte avec XPath, c'est simplement délicat. Dans tous les cas où la valeur que vous essayez de faire correspondre contient à la fois des guillemets simples et des guillemets doubles, vous pouvez construire une expression qui utilise les éléments suivants concat
pour produire le texte qu'il va faire correspondre :
elm[@att=concat('"', "'")]
Cela nous amène à ceci, qui est beaucoup plus compliqué que je ne le voudrais :
/// <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();
}
Et oui, je l'ai testé avec tous les cas limites. C'est pourquoi la logique est si stupidement complexe :
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();
}
0 votes
SomeValue est donc une variable C# ?
0 votes
Oui, c'est une variable C#. "ListObject[@Title='" + SomeValue +"']". Voici comment j'ai écrit l'expression