Это то, что я придумал
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 не так коротка, как могла бы (см. Вопрос), но достаточно близка и что-либо более оптимальное было бы очень сложным, так как вам пришлось бы искать соответствующие пары "или".