[英]Friendly way to parse XDocument
我有一个类,从中创建了各种不同的 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 类实例都会更新部分或全部值。
文档根总是非空的。
之后验证对象,因此您不必执行两次验证(一次在解析时,一次在保存前)。
代码:
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 结构上重复迭代,但是如果有一点想象力,我相信如果它成为一个问题,您可以克服它。
下面是 MyObject 的样子: public class MyObject { public string 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);
});
}
}
以下是支持它的扩展方法: public static class 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();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.