如何在Silverlight中评估XPath表达式?

时间:2010-02-24 17:36:01

标签: xml silverlight xpath

我需要允许高级用户输入XPath表达式并向其显示找到的值或节点或属性。在.Net框架中,System.Xml.XPath.Extensions可用于调用XPathEvaluate,但Silverlight没有此MSDN reference。有没有人重写过在Silverlight中使用的扩展方法?最好的方法是什么?为什么它们不能在Silverlight或工具箱中使用(vote on the issue here)?

3 个答案:

答案 0 :(得分:1)

我认为在Silverlight中没有XPath的原因是MS希望你使用Linq来代替XML。但这并不能完全帮助你。不幸的是,我觉得很难达到你想要的效果。如果您必须具有此功能,我认为您将不得不求助于将查询发送到服务器,在那里进行评估,并返回结果。这很难看,但我认为这是唯一的方法。

答案 1 :(得分:0)

一种解决方案是使用通用处理程序并在异步请求中将处理外包给服务器。这是一步一步:

<强>首先

网络项目 中创建通用处理程序。使用以下代码为ProcessRequest添加ASHX文件(简化为简洁):

    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "text/plain";

        string xml = context.Request.Form["xml"].ToString();
        string xpath = context.Request.Form["xpath"].ToString();

        XmlReader reader = new XmlTextReader(new StringReader(xml));
        XDocument doc = XDocument.Load(reader);

        var rawResult = doc.XPathEvaluate(xpath);
        string result = String.Empty;
        foreach (var r in ((IEnumerable<object>)rawResult)) 
        {
            result += r.ToString();
        }

        context.Response.Write(result);

    }

应该注意的是,有些名称空间需要引用xml处理:

  1. System.IO

  2. 的System.Xml

  3. System.Xml.XPath

  4. System.Xml.Linq的

  5. 第二名:

    您需要一些代码来允许您对通用处理程序进行异步发布。下面的代码很长,但基本上你传递了以下代码:

    1. 您的通用处理程序的Uri

    2. 键值对的字典(假设xml文档和xpath)

    3. 成功和失败的回调

    4. 对UserControl的调度计时器的引用,以便您可以在回调中访问UI(如有必要)。

    5. 以下是我在实用程序类中放置的一些代码:

      public class WebPostHelper
      {
          public static void GetPostData(Uri targetURI, Dictionary<string, string> dataDictionary, Action<string> onSuccess, Action<string> onError, Dispatcher threadDispatcher)
          {
              var postData = String.Join("&",
                              dataDictionary.Keys.Select(k => k + "=" + dataDictionary[k]).ToArray());
      
              WebRequest requ = HttpWebRequest.Create(targetURI);
              requ.Method = "POST";
              requ.ContentType = "application/x-www-form-urlencoded";
              var res = requ.BeginGetRequestStream(new AsyncCallback(
                  (ar) =>
                  {
                      Stream stream = requ.EndGetRequestStream(ar);
                      StreamWriter writer = new StreamWriter(stream);
                      writer.Write(postData);
                      writer.Close();
                      requ.BeginGetResponse(new AsyncCallback(
                              (ar2) =>
                              {
                                  try
                                  {
                                      WebResponse respStream = requ.EndGetResponse(ar2);
                                      Stream stream2 = respStream.GetResponseStream();
                                      StreamReader reader2 = new StreamReader(stream2);
                                      string responseString = reader2.ReadToEnd();
                                      int spacerIndex = responseString.IndexOf('|') - 1;
                                      string status = responseString.Substring(0, spacerIndex);
                                      string result = responseString.Substring(spacerIndex + 3);
                                      if (status == "success")
                                      {
                                          if (onSuccess != null)
                                          {
                                              threadDispatcher.BeginInvoke(() =>
                                              {
                                                  onSuccess(result);
                                              });
                                          }
                                      }
                                      else
                                      {
                                          if (onError != null)
                                          {
                                              threadDispatcher.BeginInvoke(() =>
                                              {
                                                  onError(result);
                                              });
                                          }
                                      }
                                  }
                                  catch (Exception ex)
                                  {
                                      string data2 = ex.ToString();
                                  }
                              }
                          ), null);
      
                  }), null);
          }
      }
      

      <强>第三

      调用实用程序类并传递xml和xpath:

          private void testButton_Click(object sender, RoutedEventArgs e)
          {
              Dictionary<string, string> values = new Dictionary<string, string>();
              values.Add("xml", "<Foo />");
              values.Add("xpath", "/*");
      
              //Uri uri = new Uri("http://eggs/spam.ashx");
              Uri uri = new Uri("http://localhost:3230/xPathHandler.ashx");
      
              WebPostHelper.GetPostData(uri, values,
                  (result) =>
                  {
                      MessageBox.Show("Your result " + result);
                  },
                  (errMessage) =>
                  {
                      MessageBox.Show("An error " + errMessage);
                  },
                  this.Dispatcher);
      
          }
      

      让我重申,此处的代码是 为了简洁而简化 。您可能希望使用序列化程序将更复杂的类型传递给通用处理程序。当您从context.Request.Form集合中获取值时,您将需要以防御方式编写无效的“健全性检查”。但基本思想如上所述。

答案 2 :(得分:0)

现在似乎有a NuGet package提供此功能。作者被列为Microsoft。