【问题标题】:Friendly way to parse XDocument解析 XDocument 的友好方式
【发布时间】:2012-11-16 04:18:12
【问题描述】:

我有一个创建各种不同 XML 方案的类。我通过一个(非常长的)语句使用可选元素和属性的条件运算符创建各种动态 XDocument。

我现在需要将 XDocument 转换回类,但由于它们来自不同的方案,因此许多元素和子元素可能是可选的。我知道这样做的唯一方法是使用大量 if 语句。

这种方法似乎不是很 LINQ,并且使用的代码比我创建 XDocument 时要多得多,所以我想知道是否有更好的方法来做到这一点?

一个例子是得到

<?xml version="1.0"?>
<root xmlns="somenamespace">
    <object attribute1="This is Optional" attribute2="This is required">
        <element1>Required</element1>
        <element1>Optional</element1>
        <List1>
            Optional List Of Elements
        </List1>
        <List2>
            Required List Of Elements
        </List2>
    </object>
</root>

进入

public class Object()
{
    public string Attribute1;
    public string Attribute2;
    public string Element1;
    public string Element2;
    public List<ListItem1> List1;
    public List<ListItem2> List2;
}

以比这更 LINQ 友好的方式:

public bool ParseXDocument(string xml)
{
    XNamespace xn = "somenamespace";            
    XDocument document = XDocument.Parse(xml);

    XElement elementRoot = description.Element(xn + "root");
    if (elementRoot != null)
    {
        //Get Object Element
        XElement elementObject = elementRoot.Element(xn + "object");
        if(elementObject != null)
        {
            if(elementObject.Attribute(xn + "attribute1") != null)
            {
                Attribute1 = elementObject.Attribute(xn + "attribute1");
            }
            if(elementObject.Attribute(xn + "attribute2") != null)
            {
                Attribute2 = elementObject.Attribute(xn + "attribute2");
            }
            else
            {
                //This is a required Attribute so return false
                return false;
            }
            //If, If/Elses get deeper and deeper for the next elements and lists etc.... 
        }
        else
        {
            //Object is a required element so return false
            return false;
        }
    }
    else
    {
        //Root is a required element so return false
        return false;
    }
    return true;
}

更新:只是为了澄清 ParseXDocument 方法在“Object”类中。每次收到 xml 文档时,Object 类实例都会更新其部分或全部值。

【问题讨论】:

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


    【解决方案1】:

    代码:

    private static readonly XNamespace xn = "somenamespace";
    
    public bool ParseXDocument(string xml)
    {
        XDocument document = XDocument.Parse(xml);
    
        var obj = document.Root.Element(xn + "object");
        if (obj == null)
            return false;
    
        Attribute1 = (string)obj.Attribute("attribute1");
        Attribute2 = (string)obj.Attribute("attribute2");
        Element1 = (string)obj.Element(xn + "element1");
        Element2 = (string)obj.Elements(xn + "element1").ElementAtOrDefault(1);
        // ...
    
        return Validate();
    }
    

    【讨论】:

    • 谢谢 DTB-抱歉应该让自己更清楚。我不是在创建新类,而是在更新现有类中的值。新值会定期发送,并且每个接收到的 xml 文档都会更新一些到所有值。 ParseXDocument 方法将位于“Object”类中。
    【解决方案2】:

    下面我有几个扩展方法可供您使用,它们可能有助于达到您想要的可读性。当前形式的代码不支持根据是否找到所有必需元素来返回真/假。我建议在这方面采用 dtb 的建议,只需解析出细节,然后对其进行验证。

    有一些缺点,例如对 XML 结构的重复迭代,但如果它成为一个问题,我相信你可以克服它。

    这是 MyObject 的样子: 公共类 MyObject { 公共字符串 Attribute1; 公共字符串 Attribute2; 公共字符串 Element1; 公共字符串 Element2; 公共列表 List1; 公共列表List2;

        public void ParseXDocument(string xml)
        {
            XNamespace xn = "somenamespace";            
            XDocument document = XDocument.Parse(xml);
    
            XElement elementRoot = document.Root;
            elementRoot.MatchElement(xn.GetName("object"), xObject => {
                xObject.MatchAttribute("attribute1", (x,a) => this.Attribute1 = (string)a);
                xObject.MatchAttribute("attribute2", (x,a) => this.Attribute2 = (string)a);
                xObject.MatchElement(xn.GetName("element1"), x => this.Element1 = (string)x);
                xObject.MatchElement(xn.GetName("element2"), x => this.Element2 = (string)x);
            });
        }
    }
    

    以下是支持它的扩展方法: 公共静态类 XElementExtensions {

        public static XElement MatchAttribute(this XElement x, XName name, Action<XElement, XAttribute> action) {
            foreach (var a in x.Attributes(name)) {
                action(x, a);
            }
    
            return x;
        }
    
        public static XElement MatchElement(this XElement x, XName name, Action<XElement> action) {
            foreach (var child in x.Elements(name)) {
                action(child);
            }
    
            return x;
        }
    }
    

    最后,这是我在 LinqPad 中使用的一些示例驱动程序代码来测试它:

    void Main()
    {
        var xml = @"<?xml version=""1.0""?>
    <root xmlns=""somenamespace"">
        <object attribute1=""This is Optional"" attribute2=""This is required"">
            <element1>Required</element1>
            <element2>Optional</element2>
            <List1>
                Optional List Of Elements
            </List1>
            <List2>
                Required List Of Elements
            </List2>
        </object>
    </root> 
        ";
    
        var o = new MyObject();
    
        o.ParseXDocument(xml);
        o.Dump();
    }
    

    【讨论】:

      猜你喜欢
      • 2011-03-29
      • 1970-01-01
      • 2013-07-28
      • 1970-01-01
      • 2013-08-25
      • 2017-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多