2010-02-24 61 views
5

我需要允許高級用戶輸入XPath表達式,並向他們顯示找到的值或節點或屬性。在.Net框架中,可以使用System.Xml.XPath.Extensions來調用XPathEvaluate,但Silverlight沒有這個MSDN reference。是否有人重寫了在Silverlight中使用的擴展方法?最好的方法是什麼?爲什麼不在Silverlight或工具包中提供(vote on the issue here)?如何評估Silverlight中的XPath表達式?

+0

+1我同意我希望看到自己的擴展方法的端口。 – AnthonyWJones 2010-02-24 19:21:40

+0

「高級用戶」不是開發者嗎?需要支持多大範圍的XPath? – AnthonyWJones 2010-02-25 09:03:23

+0

「高級用戶」,如某人想要如何使用Xpath而不是我創建的用於幫助他們完成此操作的其餘UI。所以他們只需要輸入xPath,我會向他們展示結果。 – Aligned 2010-02-25 20:11:09

回答

0

一種解決方案是使用通用處理程序,並將處理外包給服務器以處理異步請求。這裏是一個一步一步:

第一:

Web項目創建一個通用的處理程序。添加下面的代碼的ASHX文件爲您的ProcessRequest(簡化爲簡潔):

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.XPat^h

  4. System.Xml.Linq的

二:

你需要一些代碼,將讓你做出一個異步郵寄到通用處理器。下面的代碼是漫長的,但本質上你通過以下事項:

  1. 您的通用處理器

  2. 鍵值對(假設XML文檔中的XPath)

  3. 的字典的URI

    成功和失敗的回調

  4. 對UserControl的調度計時器的引用,以便您可以在回調中訪問您的UI(如有必要)。

下面是一些代碼,我放在一個工具類:

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集合中獲取值時,您需要以防禦性方式編寫空值守衛「完整性檢查」。但基本想法如上所述。

+0

-1。這些天我很少冷靜下來,但在這種情況下,我感到有必要這樣做。將XML編碼爲'x-www-form-urlencoded'(帶有可能會產生的各種字符編碼令人頭痛的問題),然後將其全部恢復到服務器上,以執行XPath並返回結果(這也可能很大),據我所知,也會產生難以理解的結果。 – AnthonyWJones 2010-02-25 08:16:36

+0

安東尼,我把你的罕見downvote作爲一個「好點」,但我鼓勵你提供一個解決方案。 xml文件可能非常大(例如iTunes庫),但在許多情況下,它們的設計較小(例如,典型的RSS提要)。帶有字符編碼的AJAX樣式文章(Server.UrlDecode可能應該在示例中)工作正常(取上面的代碼並實現它,你將能夠看到自己)。 – t3rse 2010-02-25 14:53:00

1

我認爲XPath在Silverlight中不可用的原因是MS希望您使用Linq來代替XML。但這並不完全有助於你。不幸的是,我認爲這將很難實現你想要的。如果您必須具備此功能,我認爲您將不得不求助於將查詢發送到服務器,在那裏對其進行評估並返回結果。這是醜陋的,但我認爲這是唯一的方法。

+0

我非常懷疑微軟__want__你使用Linq。考慮到希望將下載量降到最低,並且Linq非常擅長用XPath處理它未優先處理的事實,它更有可能。 – AnthonyWJones 2010-02-24 19:21:09

+2

事實證明,XPath支持在Silverlight 4中可用: http://programmerpayback.com/2010/04/01/xpath-support-in-silverlight-4-xpathpad/ – 2010-04-06 08:35:49