XPath(v1)无法编码表达式。
如果您只有单个或双引号,那么您可以使用
等表达式//review[@name="Bob's Pizza"]
//review[@name='"Pizza" Pam']
但如果你有[弗雷德的“Fancy Pizza”]那么你必须使用这样的Escaping Strings in XPath (C++)来生成
//review[@name=Concat("Fred's ",'"Fancy Pizza"')]
任何人都有c#函数来执行此操作吗?
一些关闭的链接
编辑:一些答案建议使用'
和“"
转义”但是这有道理它不起作用;尝试使用XML片段:
<review name="Bob's Pizza"/>
和xpath
//review[@name='Bob's Pizza']
答案 0 :(得分:10)
虽然它肯定不会在所有情况下都有效,但这是一种回避问题的方法:
doc.DocumentElement.SetAttribute("searchName", name);
XmlNode n = doc.SelectNodes("//review[@name=/*/@searchName]");
答案 1 :(得分:9)
$('your-select-element').selectUtils('setEmpty');
答案 2 :(得分:7)
我需要这个,所以我为C#创建了这个解决方案。
/// <summary>
/// Returns a valid XPath statement to use for searching attribute values regardless of 's or "s
/// </summary>
/// <param name="attributeValue">Attribute value to parse</param>
/// <returns>Parsed attribute value in concat() if needed</returns>
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();
}
答案 3 :(得分:4)
这就是我提出的
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操作并不尽可能短(请参阅问题)但是它足够接近并且任何更优化都会非常复杂,因为您必须寻找匹配的“或”对。
答案 4 :(得分:4)
到目前为止,我遇到了所有解决方案的问题。一个有额外的文本部分(例如'“'或”'“)可以打破你正在寻找的东西。一个文本在最后一个引用/ 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) & "]")
答案 5 :(得分:2)
我需要在XSLT本身中执行此操作,因此根据此页面上的答案提出以下内容:
<xsl:template name="escape-string">
<xsl:param name="string"/>
<xsl:param name="concat" select="true()"/>
<xsl:variable name="quote">"</xsl:variable>
<xsl:variable name="apos">'</xsl:variable>
<xsl:choose>
<xsl:when test="not(contains($string, $apos))">'<xsl:value-of select="$string"/>'</xsl:when>
<xsl:when test="not(contains($string, $quote))">"<xsl:value-of select="$string"/>"</xsl:when>
<xsl:otherwise>
<xsl:if test="$concat">concat(</xsl:if>
<xsl:call-template name="escape-string">
<xsl:with-param name="string" select="substring-before($string, $apos)"/>
<xsl:with-param name="concat" select="false()"/>
</xsl:call-template>
<xsl:text>, "'", </xsl:text>
<xsl:call-template name="escape-string">
<xsl:with-param name="string" select="substring-after($string, $apos)"/>
<xsl:with-param name="concat" select="false()"/>
</xsl:call-template>
<xsl:if test="$concat">)</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
答案 6 :(得分:1)
另一种变化......我的concat()部分有点懒,但至少它使用整个值。
/// <summary>
/// Returns an XPath string literal to use for searching attribute values (wraped in apostrophes, quotes, or as a concat function).
/// </summary>
/// <param name="attributeValue">Attribute value to encode and wrap.</param>
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("\"", "\",'\"',\""));
}
}
答案 7 :(得分:1)
加入乐趣
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
答案 8 :(得分:-1)
报价:
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) + "]“);
或者只是像之前的帖子那样建议。使用&amp;和&amp; quot;
替换'和'