[英]Dynamic Linq to Xml example
我需要一個有關如何在Xml中使用System.Linq.Dynamic的基本示例。 這是我要轉換為動態Linq的有效語句:
XElement e = XElement.Load(new XmlNodeReader(XmlDoc));
var results =
from r in e.Elements("TABLES").Descendants("AGREEMENT")
where (string)r.Element("AGRMNT_TYPE_CODE") == "ISDA"
select r.Element("DATE_SIGNED");
foreach (var x in results)
{
result = x.Value;
break;
}
這是我使用的方法:
string whereClause = "(\"AGRMNT_TYPE_CODE\") == \"ISDA\"";
string selectClause = "(\"DATE_SIGNED\")";
var results = e.Elements("TABLES").Descendants<XElement>("AGREEMENT").
AsQueryable<XElement>().
Where<XElement>(whereClause).
Select(selectClause);
foreach (var x in results)
{
result = (string)x;
break;
}
它執行沒有錯誤,但是沒有結果。
我正在嘗試編寫類似於http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query中找到的規范示例的代碼-library.aspx ,其中對數據庫應用構造的字符串:
Dim Northwind as New NorthwindDataContext
Dim query = Northwind.Products _
.Where("CategoryID=2 and UnitPrice>3") _
.OrderBy("SupplierId")
GridView1.Datasource = query
GridView1.Databind()
我想念什么?
我終於讓它工作了。 我放棄了最初的方法,因為到目前為止,我還不確定它是否打算與Xml一起使用。 我幾乎看不到任何地方都在反對該聲明。 相反,我使用Jon Skeet對這個問題的回答作為我回答的基礎:
XElement e = XElement.Load(new XmlNodeReader(XmlDoc));
List<Func<XElement, bool>> exps = new List<Func<XElement, bool>> { };
exps.Add(GetXmlQueryExprEqual("AGRMNT_TYPE_CODE", "ISDA"));
exps.Add(GetXmlQueryExprNotEqual("WHO_SENDS_CONTRACT_IND", "X"));
List<ConditionalOperatorType> condOps = new List<ConditionalOperatorType> { };
condOps.Add(ConditionalOperatorType.And);
condOps.Add(ConditionalOperatorType.And);
//Hard-coded test value of the select field Id will be resolved programatically in the
//final version, as will the preceding literal constants.
var results = GetValueFromXml(171, e, exps, condOps);
foreach (var x in results)
{
result = x.Value;
break;
}
return result;
...
public static Func<XElement, bool> GetXmlQueryExprEqual(string element, string compare)
{
try
{
Expression<Func<XElement, bool>> expressExp = a => (string)a.Element(element) == compare;
Func<XElement, bool> express = expressExp.Compile();
return express;
}
catch (Exception e)
{
return null;
}
}
public static Func<XElement, bool> GetXmlQueryExprNotEqual(string element, string compare)
{
try
{
Expression<Func<XElement, bool>> expressExp = a => (string)a.Element(element) != compare;
Func<XElement, bool> express = expressExp.Compile();
return express;
}
catch (Exception e)
{
return null;
}
}
private IEnumerable<XElement> GetValueFromXml(int selectFieldId, XElement elem,
List<Func<XElement, bool>> predList, List<ConditionalOperatorType> condOpsList)
{
try
{
string fieldName = DocMast.GetFieldName(selectFieldId);
string xmlPathRoot = DocMast.Fields[true, selectFieldId].XmlPathRoot;
string xmlPathParent = DocMast.Fields[true, selectFieldId].XmlPathParent;
IEnumerable<XElement> results = null;
ConditionalOperatorType condOp = ConditionalOperatorType.None;
switch (predList.Count)
{
case (1):
results =
from r in elem.Elements(xmlPathRoot).Descendants(xmlPathParent)
where (predList[0](r))
select r.Element(fieldName);
break;
case (2):
CondOp = (ConditionalOperatorType)condOpsList[0];
switch (condOp)
{
case (ConditionalOperatorType.And):
results =
from r in elem.Elements(xmlPathRoot).Descendants(xmlPathParent)
where (predList[0](r) && predList[1](r))
select r.Element(fieldName);
break;
case (ConditionalOperatorType.Or):
results =
from r in elem.Elements(xmlPathRoot).Descendants(xmlPathParent)
where (predList[0](r) || predList[1](r))
select r.Element(fieldName);
break;
default:
break;
}
break;
default:
break;
}
return results;
}
catch (Exception e)
{
return null;
}
}
但是,這種方法顯然遠非完美。
任何想法或建議將不勝感激。
實際上,您的where子句有兩個問題:
("AGMNT_TYPE_CODE") == "ISDA"
...當然會計算為false
,因為它們都是字符串。
第二個問題是ExpressionParser
范圍受到限制,它只能對一組預定義類型進行比較。 你需要重新編譯的動態庫,要么允許一些其他類型的(你可以通過修改為此predefinedTypes
中的靜態字段ExpressionParser
或類型),去掉勾選的預定義的類型(這是我以前做了):
Expression ParseMemberAccess(Type type, Expression instance)
{
// ...
switch (FindMethod(type, id, instance == null, args, out mb))
{
case 0:
throw ParseError(errorPos, Res.NoApplicableMethod,
id, GetTypeName(type));
case 1:
MethodInfo method = (MethodInfo)mb;
//if (!IsPredefinedType(method.DeclaringType)) // Comment out this line, and the next.
//throw ParseError(errorPos, Res.MethodsAreInaccessible, GetTypeName(method.DeclaringType));
if (method.ReturnType == typeof(void))
throw ParseError(errorPos, Res.MethodIsVoid,
id, GetTypeName(method.DeclaringType));
return Expression.Call(instance, (MethodInfo)method, args);
default:
throw ParseError(errorPos, Res.AmbiguousMethodInvocation,
id, GetTypeName(type));
}
// ...
}
我注釋掉的那些行是檢查預定義類型的地方。
進行更改后,您需要更新查詢(請記住, ExpressionParser
會生成已編譯的表達式,因此僅使用"(\\"AGRMNT_TYPE_CODE\\") == \\"ISDA\\""
。您將需要以下內容:
string where = "Element(\"AGMNT_TYPE_CODE\").Value == \"ISDA\"";
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.