【问题标题】:match xml element with given namespace qualified attribute using XDocument使用 XDocument 将 xml 元素与给定的命名空间限定属性匹配
【发布时间】:2014-12-19 11:35:39
【问题描述】:

我正在尝试使用以下方法从 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 初始化为所需的值。

【问题讨论】:

  • 你能发布一个包含sdata定义的XML块吗?不仅仅是元素。
  • @RahulSingh 我用完整的 xml 文档的示例编辑了问题

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


【解决方案1】:

答案:

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 =&gt; y.Attribute(name).Value.Equals(id.ToString())) 是危险的。如果您正在寻找名为"depotStore" 的元素,但那里没有名为"sdata:uuid" 的属性怎么办? (它会抛出一个空异常)。您应该检查 null 或使用 Attributes().Any()

【讨论】:

    【解决方案2】:

    我现在已通过将方法更改为来解决此问题

    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 以在 where 中使用是诀窍。

    【讨论】:

      猜你喜欢
      • 2016-02-19
      • 1970-01-01
      • 1970-01-01
      • 2011-11-08
      • 2011-04-06
      • 1970-01-01
      • 1970-01-01
      • 2012-01-11
      • 2017-03-23
      相关资源
      最近更新 更多