目标:
实现类似于SQL的where条件方式从XML中查询出满足指定属性值的元素集合,并可通用到其它XML文档。
平台及工具:
-
windows7 旗舰版
-
VS2008
问题:
当生成的XPath字符串包含两个字符属性条件时出现异常“具有无效标记”。
根据提供的元素属性名称数组及其对应的值数组合成XPath字符串,然后使用XPathSelectElements函数查询所有满足条件的元素集合,以下面的简单用户信息XML文档为例:
<?xml version="1.0" encoding="utf-8"?>
<Users>
<User ID="U001" UserName="Jack" age="20" DeptID="D001" />
<User ID="U002" UserName="Tom" age="22" DepatID="D002" />
<User ID="U003" UserName="Jerry" age="25" DepatID="D002" />
</Users>
通过以下函数查询出满足条件的元素集合:
/// <summary>
/// 根据指定属性和值条件查找元素
/// </summary>
/// <param name="columns">元素属性名称数组</param>
/// <param name="values">元素属性对应的值数组</param>
/// <returns></returns>
public List<XElement> FindElements(string[] columns, string[] values)
{
if (columns.Count() != values.Count())
{
throw new Exception("条件字段数目和值数目不匹配,无法生成查询条件!");
}
//循环逐个查找到满足条件的元素
StringBuilder xpath = new StringBuilder(xTableName + "[");
for (short index = 0; index < columns.Count(); index++)
{
//增加and逻辑运算符
if (index > 0)
{
xpath.Append(" AND");
}
xpath.Append(columns[index]);
xpath.Append("=");
xpath.Append("'" + values[index] + "'");
}
xpath.Append("]");
//根据xpath进行查询
return xmlDB.XPathSelectElements(xpath.ToString());
}
如果是单个属性作为条件,能够正确找到需要的元素;如果为多个元素属性作为条件,而且其中包含多个字符串类型条件将产生具有无效标记的异常,跟踪xpath.ToString()生成的查询条件及其结果为:
XPath字符串 | 结果 |
---|---|
User[@ID='U001'] | 成功 |
User[@ID='U001' AND @Age=20] | 成功 |
User[@Age=20] | 成功 |
User[@Age>20] | 成功 |
User[@ID='U001' AND @UserName='Jack'] | 异常 |
User[@ID='' AND @UserName=''] | 异常 |
User[@ID=\"U001\" AND @UserName=\"Jack\"] | 异常 |
User[@ID=\'U001\' AND @UserName=\'Jack\'] | 异常 |
@"User[@ID=\'U001\' AND @UserName=\'Jack\']" | 异常 |
为达到同样的目的只能采用折衷方式,根据提供的元素属性条件逐个提取满足条件的元素,如果数据量太大将会影响性能:
public List<XElement> FindElements(string[] columns, string[] values)
{
List<XElement> nodes = null,filterNodes = null;
if (columns.Count() != values.Count())
{
throw new Exception("条件字段数目和值数目不匹配,无法生成查询条件!");
}
//循环逐个查找到满足条件的元素
for (short index = 0; index < columns.Count(); index++)
{
string value = values[index];
string atrrName = columns[index];
//初始化列表
if (index == 0)
{
IEnumerable<XElement> elements = xmlTable.XPathSelectElements(xTableName + "[@" + columns[index] + "='" + value + "']");
if (elements == null || elements.Count<XElement>() == 0)
return null;
else
{
nodes = elements.ToList<XElement>();
elements = null;
continue;
}
}
if (nodes == null)
{
return null;
}
//按条件过滤数据
var data = from e in nodes
where e.Attribute(atrrName).Value == value
select e;
filterNodes = data.ToList<XElement>();
if (filterNodes == null || filterNodes.Count<XElement>() == 0)
return null;
nodes = filterNodes;
}
//根据xpath进行查询
if(nodes==null || nodes.Count<XElement>() == 0)
{
return null;
}
else
{
return nodes;//.First<XElement>();
}
}