XML linq需要关于异常的详细信息

时间:2014-11-08 10:27:10

标签: c# xml linq exception detail

我在我的项目中使用xml linq。我正在处理非常大的xml,以便于理解,我已经提到了小样本xml。

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
    <StackOverflowReply xmlns="http://xml.stack.com/RRAND01234">
        <processStatus>
            <statusCode1>P</statusCode1>
            <statusCode2>P</statusCode2>
            <statusCode3>P</statusCode3>
            <statusCode4>P</statusCode4>
        </processStatus>
    </StackOverflowReply>
</soap:Body>

以下是C#xml linq

XNamespace x = "http://xml.stack.com/RRAND01234";
var result = from StackOverflowReply in XDocument.Parse(Myxml).Descendants(x + "Security_AuthenticateReply")
             select new
             {
                status1 = StackOverflowReply.Element(x + "processStatus").Element(x + "statusCode1").Value,
                status2 = StackOverflowReply.Element(x + "processStatus").Element(x + "statusCode2").Value,
                status3 = StackOverflowReply.Element(x + "processStatus").Element(x + "statusCode3").Value,
                status4 = StackOverflowReply.Element(x + "processStatus").Element(x + "statusCode4").Value,
                status5 = StackOverflowReply.Element(x + "processStatus").Element(x + "statusCode5").Value,
              };

这里我得到的异常就像“对象引用未设置为对象的实例”。因为标签

<statusCode5>

不在我的xml中。在这种情况下,我想得到详细的异常消息,如“Missing tag statusCode5”。请引导我如何从我的例外中获取此消息。

1 个答案:

答案 0 :(得分:0)

在LINQ to XML语句中,确切地找出缺少的元素是不容易的(我知道的)。然而,你可以做的是在元素上使用(string)来处理缺失的元素 - 但如果你有一系列元素,这可能会变得棘手。

这不适用于您当前的代码:

status5 = (string)StackOverflowReply.Element(x + "processStatus").Element(x + "statusCode5")

Becuase(string)仅适用于第一个元素,第二个元素是缺少的元素。

您可以将LINQ更改为仅关注子节点,如下所示:

XNamespace x = "http://xml.stack.com/RRAND01234";
var result = from StackOverflowReply in XDocument.Parse(Myxml).Descendants(x + "processStatus")
         select new
         {
            status1 = (string)StackOverflowReply.Element(x + "statusCode1"),
            status2 = (string)StackOverflowReply..Element(x + "statusCode2"),
            status3 = (string)StackOverflowReply..Element(x + "statusCode3"),
            status4 = (string)StackOverflowReply.Element(x + "statusCode4"),
            status5 = (string)StackOverflowReply.Element(x + "statusCode5"),
          };

但是,如果您的XML很复杂并且您有不同的深度(嵌套元素),那么您需要一个更强大的解决方案来避免一堆条件运算符检查或多个查询。

如果是这种情况,我会有所帮助 - 我必须深入挖掘。

编辑更复杂的XML

我在工作中遇到的一些XML也面临着类似的挑战。代替一种简单的方法来确定哪个节点是违规节点,并且不想拥有可怕的长三元运算符,我编写了一个扩展方法,该方法从指定的起始节点递归到我正在寻找的节点。

这是一个有点简单和人为的例子来展示。

<SomeXML>
  <Tag1>
    <Tag1Child1>Value1</Tag1Child1>
    <Tag1Child2>Value2</Tag1Child2>
    <Tag1Child3>Value3</Tag1Child3>
    <Tag1Child4>Value4</Tag1Child4>
  </Tag1>
  <Tag2>
    <Tag2Child1>
      <Tag2Child1Child1>SomeValue1</Tag2Child1Child1>
      <Tag2Child1Child2>SomeValue2</Tag2Child1Child2>
      <Tag2Child1Child3>SomeValue3</Tag2Child1Child3>
      <Tag2Chidl1Child4>SomeValue4</Tag2Child1Child4>
    <Tag2Child1>
    <Tag2Child2>
      <Tag2Child2Child1>
        <Tag2Child2Child1Child1 />
        <Tag2Child2Child1Child2 />
    </Tag2Child2>
  </Tag2>
</SomeXML>

在上面的XML中,我无法知道(在解析之前)是否有任何子元素是空的,所以在经过一些搜索和调整后,我想出了以下扩展方法:

public static XElement GetChildFromPath(this XElement currentElement, List<string> elementNames, int position = 0)
{

    if (currentElement == null || !currentElement.HasElements)
    {
        return currentElement;
    }

    if (position == elementNames.Count - 1)
    {
        return currentElement.Element(elementNames[position]);
    }
    else
    {
        XElement nextElement = currentElement.Element(elementNames[position]);
        return GetChildFromPath(nextElement, elmenentNames, position + 1);
    }
}

基本上,该方法将XElement调用它,加上路径顺序中的List<string>元素,我想要的那个作为最后一个元素,以及一个位置(列表中的索引) ),然后沿路径工作,直到找到有问题的元素或用完路径中的元素。它并不像我希望的那样优雅,但我没有时间重构它。

我会像这样使用它(基于上面的示例XML):

MyClass myObj = (from x in XDocument.Parse(myXML).Descendants("SomeXML")
                select new MyClass() {
                    Tag1Child1 = (string)x.GetChildFromPath(new List<string>() {
                                 "Tag1", "Tag1Child1" }),
                    Tag2Child1Child4 = (string)x.GetChildFromPath(new List<string>() {
                                 "Tag2", "Tag2Child1", "Tag2Child1Child4" }),
                    Tag2Child2Child1Child2 = (string)x.GetChildFromPath(new List<string>() {
                                 "Tag2", "Tag2Child2", "Tag2Child2Child1", 
                                 "Tag2Child2Child1Child2" })
                }).SingleOrDefault();

不像我想的那样优雅,但至少它允许我解析一个可能缺少节点但没有吹出块的XML文档。另一种选择是做一些事情:

Tag2Child2Child1Child1 = x.Element("Tag2") == null ? 
                         "" : x.Element("Tag2Child2") == null ? 
                         "" : x.Element("Tag2Child2Child1") == null ? 
                         "" : x.Element("Tag2Child2Child1Child2") == null ? 
                         "" : x.Element("Tag2")
                               .Element("Tag2Child2")
                               .Element("Tag2Child2Child1") 
                               .Element("Tag2Child2Child1Child2").Value

对于具有许多属性的对象来说,这会变得非常难看。

无论如何,如果这是有用的,您可以根据需要随意使用/改编/修改。