Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/344.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# XPATH查询中的特殊字符_C#_Java_Xml_Xpath - Fatal编程技术网

C# XPATH查询中的特殊字符

C# XPATH查询中的特殊字符,c#,java,xml,xpath,C#,Java,Xml,Xpath,我使用下面的XPATH查询列出站点下的对象列表对象[@Title='SomeValue']。有些价值观是动态的。只要SomeValue没有撇号('),此查询就可以工作。也尝试使用转义序列。没用 我做错了什么?如果在某个值中没有任何双引号,则可以使用转义双引号来指定在XPath搜索字符串中搜索的值 ListObject[@Title=\"SomeValue\"] 编辑:在进行了大量的单元测试并检查后,我对我的函数进行了如下修改: public static string ToXPath(stri

我使用下面的
XPATH查询
列出站点下的对象<代码>列表对象[@Title='SomeValue']。有些价值观是动态的。只要SomeValue没有撇号('),此查询就可以工作。也尝试使用转义序列。没用


我做错了什么?

如果在某个值中没有任何双引号,则可以使用转义双引号来指定在XPath搜索字符串中搜索的值

ListObject[@Title=\"SomeValue\"]

编辑:在进行了大量的单元测试并检查后,我对我的函数进行了如下修改:

public static string ToXPath(string value) {

    const string apostrophe = "'";
    const string quote = "\"";

    if(value.Contains(quote)) {
        if(value.Contains(apostrophe)) {
            throw new XPathException("Illegal XPath string literal.");
        } else {
            return apostrophe + value + apostrophe;
        }
    } else {
        return quote + value + quote;
    }
}
XPath似乎根本没有字符转义系统,它实际上相当原始。很明显,我原来的代码只是碰巧起作用。我为误导任何人而道歉

以下原始答案仅供参考-请忽略

为了安全起见,请确保对XPath字符串中所有5个预定义XML实体的任何事件都进行转义,例如:

public static string ToXPath(string value) {
    return "'" + XmlEncode(value) + "'";
}

public static string XmlEncode(string value) {
    StringBuilder text = new StringBuilder(value);
    text.Replace("&", "&amp;");
    text.Replace("'", "&apos;");
    text.Replace(@"""", "&quot;");
    text.Replace("<", "&lt;");
    text.Replace(">", "&gt;");
    return text.ToString();
}
公共静态字符串路径(字符串值){
返回“'”+XmlEncode(值)+“'”;
}
公共静态字符串XmlEncode(字符串值){
StringBuilder文本=新的StringBuilder(值);
文本。替换(“&”、“&;”;
文本。替换(“”,“&apos;”);
文本。替换(@“”,“”);
文本。替换(“,”);
返回text.ToString();
}

我以前做过,效果很好。如果它对您不起作用,可能您需要让我们了解这个问题的其他背景。

这是一件非常困难的事情

看看,您将看到它将文字定义为:

Literal ::=   '"' [^"]* '"' 
            | "'" [^']* "'"
也就是说,XPath表达式中的字符串文本可以包含撇号或双引号,但不能同时包含两者

您不能使用转义来回避此问题。类似这样的文字:

'Some&apos;Value'
var value = "Some value with 'apostrophes' and \"quotes\"";

// doc is an instance of XElement or XDocument
IEnumerable<XElement> nodes = 
                      doc.Descendants("ListObject")
                         .Where(lo => (string)lo.Attribute("Title") == value);
var value = "Some value with 'apostrophes' and \"quotes\"";

var variableContext = new VariableContext { { "matchValue", value } };
// ixn is an instance of IXPathNavigable
XPathNodeIterator nodes = ixn.CreateNavigator()
                             .SelectNodes("ListObject[@Title = $matchValue]", 
                                          variableContext);
将匹配此XML文本:

Some&amp;apos;Value
这意味着可能存在无法生成XPath文本来匹配的XML文本,例如:

<elm att="&quot;&apos"/>
这就引出了这个问题,比我想象的要复杂得多:

/// <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();
}

我之前遇到过这个问题,看起来最简单但不是最快的解决方案是,在XML文档中添加一个新节点,该节点具有值为“SomeValue”的属性,然后使用简单的xpath搜索来查找该属性值。完成操作后,可以删除“临时节点”“从XML文档中

这样,整个比较都发生在“内部”,因此您不必构造奇怪的XPath查询

我似乎记得,为了加快速度,应该将temp值添加到根节点


祝你好运…

我将Robert的答案移植到Java(在1.6中测试):

//
///如果可能,生成一个等于该值的XPath文本;如果没有,生产
///将匹配该值的XPath表达式。
///
///请注意,如果值为
///包含长时间的双引号。
/// 
///要匹配的值。
///如果该值仅包含单引号或双引号,则XPath
///等于该值的文本。如果同时包含这两个表达式,则为XPath表达式,
///使用concat(),其计算结果为值。
公共静态字符串XPathLiteral(字符串值){
如果(!value.contains(“\”)和(&!value.contains(“')){
返回“'”+值+“'”;
}
//如果该值仅包含单引号或双引号,请构造
//XPath文本
如果(!value.contains(“\”)){
System.out.println(“不包含引号”);
字符串s=“\”+值+“\”;
系统输出打印项次;
返回s;
}
如果(!value.contains(“')){
System.out.println(“不包含撇号”);
字符串s=“””+值+“”;
系统输出打印项次;
返回s;
}
//如果该值同时包含单引号和双引号,请构造
//将所有非双引号子字符串与
//引用,例如:
//
//concat(“foo”、“bar”、“foo”)
StringBuilder sb=新的StringBuilder();
某人附加(“concat”);
String[]substring=value.split(“\”);
for(int i=0;i0);
如果(!子字符串[i].等于(“”){
如果(i>0){
某人加上(“,”);
}
某人加上“\”;
sb.追加(子串[i]);
某人加上“\”;
needComma=true;
}
if(i

希望这对某人有所帮助!

以下是Robert Rossney的StringBuilder方法的替代方法,也许更直观:

    /// <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.
    /// 
    /// From: http://stackoverflow.com/questions/1341847/special-character-in-xpath-query
    /// </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>
    public 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")

        List<string> parts = new List<string>();

        // First, put a '"' after each component in the string.
        foreach (var str in value.Split('"'))
        {
            if (!string.IsNullOrEmpty(str))
                parts.Add('"' + str + '"'); // (edited -- thanks Daniel :-)

            parts.Add("'\"'");
        }

        // Then remove the extra '"' after the last component.
        parts.RemoveAt(parts.Count - 1);

        // Finally, put it together into a concat() function call.
        return "concat(" + string.Join(",", parts) + ")";
    }
//
///如果可能,生成一个等于该值的XPath文本;如果不是,则生成
///将匹配该值的XPath表达式。
/// 
///请注意,如果值为
///包含长时间的双引号。
/// 
///发件人:http://stackoverflow.com/questions/1341847/special-character-in-xpath-query
/// 
///要匹配的值。
///如果该值仅包含单引号或双引号,则XPath
///等于值的文本。如果它同时包含这两个值,则为XPath表达式,
///使用concat(),其计算结果为值。
公共静态字符串XPathLiteral(字符串值)
{
//如果该值仅包含单引号或双引号,则为cons
    /// <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.
    /// 
    /// From: http://stackoverflow.com/questions/1341847/special-character-in-xpath-query
    /// </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>
    public 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")

        List<string> parts = new List<string>();

        // First, put a '"' after each component in the string.
        foreach (var str in value.Split('"'))
        {
            if (!string.IsNullOrEmpty(str))
                parts.Add('"' + str + '"'); // (edited -- thanks Daniel :-)

            parts.Add("'\"'");
        }

        // Then remove the extra '"' after the last component.
        parts.RemoveAt(parts.Count - 1);

        // Finally, put it together into a concat() function call.
        return "concat(" + string.Join(",", parts) + ")";
    }
XPathFactory xpf = XPathFactory.newInstance();
final Map<String, Object> variables = new HashMap<>();
xpf.setXPathVariableResolver(new XPathVariableResolver() {
  public Object resolveVariable(QName name) {
    return variables.get(name.getLocalPart());
  }
});

XPath xpath = xpf.newXPath();
XPathExpression expr = xpath.compile("ListObject[@Title=$val]");
variables.put("val", someValue);
NodeList nodes = (NodeList)expr.evaluate(someNode, XPathConstants.NODESET);
element.XPathSelectElements(String.Format("//group[@title=\"{0}\"]", "Man's"));
let quoteString (s : string) =
    if      not (s.Contains "'" ) then sprintf "'%s'"   s
    else if not (s.Contains "\"") then sprintf "\"%s\"" s
    else "concat('" + s.Replace ("'", "', \"'\", '") + "')"
var value = "Some value with 'apostrophes' and \"quotes\"";

// doc is an instance of XElement or XDocument
IEnumerable<XElement> nodes = 
                      doc.Descendants("ListObject")
                         .Where(lo => (string)lo.Attribute("Title") == value);
IEnumerable<XElement> nodes = from lo in doc.Descendants("ListObject")
                              where (string)lo.Attribute("Title") == value
                              select lo;
var value = "Some value with 'apostrophes' and \"quotes\"";

var variableContext = new VariableContext { { "matchValue", value } };
// ixn is an instance of IXPathNavigable
XPathNodeIterator nodes = ixn.CreateNavigator()
                             .SelectNodes("ListObject[@Title = $matchValue]", 
                                          variableContext);