使用XDocument将xml元素与给定的名称空间限定属性匹配

时间:2014-12-19 11:35:39

标签: c# xml linq linq-to-xml

我正在尝试使用以下内容从XDocument中提取元素:

    private bool ContainsEntity(FileInfo filePath, string entityType, int id, string field, string value)
    {
        try{
        var doc = XDocument.Load(filePath.FullName);
        var entities = doc.Descendants(entityType);
        var ns = XNamespace.Get("http://schemas.sage.com/sdata/2008/1");
        var attr = new XAttribute(ns + "uuid", id);
        var specificEntities = entities.Where(y =>
            {
                var atts = y.Attributes();
                return atts.Contains(attr);
            });
        return specificEntities.Any(ent =>
            ent.Elements(field).Any(f => f.Value.Equals(value, StringComparison.OrdinalIgnoreCase)));

        }catch{return false;}
    }

xml文档中的相关元素如下所示:

 <?xml version=""1.0"" encoding=""utf-8""?>
<feed xmlns=""http://www.w3.org/2005/Atom"" xmlns:sdata=""http://schemas.sage.com/sdata/2008/1"" xmlns:http=""http://schemas.sage.com/sdata/http/2008/1"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:mybi=""http://schemas.sage.com/mybi/import/2011"" xmlns:cs=""urn:cs"">
<author>
<name>Sage UK</name>
</author>
<category />
<generator version=""Sage Business Sync 1.0.0.0, Resources Package 0.1.0"" />
<id />
<title>Sage 200 UK Synchronization feed</title>
<mybi:contractVersion>1.2.5</mybi:contractVersion>
<mybi:resourceKind>depotStore</mybi:resourceKind>
<entry xmlns="""">
  <author>
  <name>Sage UK</name>
</author>
<id>1</id>
<title>operatingCompanyResource</title>
<updated>2014-12-19T10:32:43.501+00:00</updated>
<sdata:payload>
  <depotStore sdata:uuid=""1"">
    <operatingCompanyReference>1</operatingCompanyReference>
    <originalType>
        operatingCompanyWarehouse
      </originalType>
    <type>
        operatingCompanyWarehouse
      </type>
    <name>warehouse1</name>
  </depotStore>
</sdata:payload>
</entry>
</feed>";

问题是属性不匹配,因此specificEntities始终是零长度集合。问题似乎是属性名称的名称空间前缀,但我看不到如何将attr初始化为所需的值。

2 个答案:

答案 0 :(得分:0)

我现在通过将方法更改为

来解决此问题
private bool ContainsEntity(FileInfo filePath, string entityType, int id, string field, string value)
{
    try{
    var doc = XDocument.Load(filePath.FullName);
    var entities = doc.Descendants(entityType);
    XNamespace ns = "http://schemas.sage.com/sdata/2008/1";
    XName name = ns + "uuid";
    var specificEntities = entities.Where(y => y.Attribute(name).Value.Equals(id));
    return specificEntities.Any(ent =>
        ent.Elements(field).Any(f => f.Value.Equals(value, StringComparison.OrdinalIgnoreCase)));

    }catch{return false;}
}

似乎创建一个显式XName以便在哪里使用。

答案 1 :(得分:0)

答案:

var specificEntities = entities
    .Where(y => y.Attributes(nsSys + "uuid").Any(a=>a.Value.Equals(id.ToString())));

或:

var specificEntities = entities
    .Where(y => y.Attributes().Any(a => a.Name==(nsSys + "uuid") && a.Value.Equals(id.ToString())));

为什么:

  • 您无法创建类似此var attr = new XAttribute(ns + "uuid", id);的属性,并且期望它等于xml文档中的某个属性。新属性不属于文档,因此命名空间的别名是随机的(当然不是“sdata”)
  • 由于这个原因你也不能使用Attributes().Contains(attr)(也因为它比较了对象的引用而不是对象本身)
  • id是一个int,因此您应该将其转换为字符串,然后再将其与某个属性(即字符串)的值进行比较。否则Equals()方法将再次比较对象,并且“1”=! 1
  • 另外,使用entities.Where(y => y.Attribute(name).Value.Equals(id.ToString()))在这里很危险。如果您正在寻找名为"depotStore"的元素,并且那里没有名为"sdata:uuid"的属性,该怎么办? (这会引起一种误解)。您应该检查null或使用Attributes().Any()