尝试使用Linq查询的问题。找不到xml元素

时间:2018-10-01 23:20:44

标签: c# .net linq

有人可以协助解决此.NET Linq查询问题。它应该工作,但是不行,并且找不到元素。该查询的结果应为106492,但只返回null。太棒了!

这是.Net小提琴代码:

using System;
using System.Xml.Linq;          
using System.Linq;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        String rxml = @"<TestMessage>
          <TestIdentification>
            <TestID>106491</TestID>
            <TestType>TESTID1</TestType>
          </TestIdentification>
          <TestIdentification>
            <TestID>106492</TestID>
            <TestType>TESTID2</TestType>
          </TestIdentification>
          <TestIdentification>
            <TestID>106493</TestID>
            <TestType>TESTID3</TestType>
          </TestIdentification>
          <TestIdentification>
            <TestID>106494</TestID>
            <TestType>TESTID4</TestType>
          </TestIdentification>
          </TestMessage>
          ";

        XElement xml = XElement.Parse(rxml);

        // Read all response fields responseLog class
        var testObj = (from el in xml.DescendantsAndSelf()
                       select new TestClassObj
                       {
                            TestID = el.Elements("TestIdentification").Elements("TestType").
                                       Where( c => c.Value == "TESTID2" ).Elements("TestID").
                                       Where( c => !string.IsNullOrWhiteSpace(c.Value)).FirstOrDefault().Value,
                     }).FirstOrDefault();

    if( testObj != null )
        Console.WriteLine(testObj.TestID);

    }
}

public class TestClassObj
{
    public String TestID{ get; set; }
    public String TestText{ get; set; }
}

3 个答案:

答案 0 :(得分:4)

首先,我删除了“外部”查询部分:

(from el in xml.DescendantsAndSelf()
 select new TestClassObj { ... }).FirstOrDefault()

鉴于您选择的TestIdentification元素仅在根元素的正下方,因此该查询是没有意义的-它只会为根元素找到任何内容。

接下来,我已经删除了TestClassObj的用法-您仅将其用作包装字符串的方式,因此您最好直接使用该字符串。

接下来,更改查询的焦点:您不是要查找TestType元素,而是要找到一个具有正确的TestIdentification子元素的TestType元素。然后,您可以找到同一TestID元素的TestIdentification元素。

接下来,我使用了从XElementstring的转换,而不是使用Value属性。在对null元素进行调用时,强制转换只会返回null,而不是抛出NullReferenceException。当您只想忽略没有预期子元素/属性的元素时,这是LINQ to XML中非常有用的方法。

剩下的是:

    var testId = xml.Elements("TestIdentification")
                    .Where(x => (string) x.Element("TestType") == "TESTID2")
                    .Select(x => (string) x.Element("TestID"))
                    .FirstOrDefault();

    Console.WriteLine(testId);

这将按预期打印出106492。

另一种选择是找到合适的TestType元素,然后导航到其父元素并找到其TestID子元素:

var testId = xml.Elements("TestIdentification")
                .Elements("TestType")                      
                .Where(x => (string) x == "TESTID2")
                .Select(x => (string) x.Parent.Element("TestID"))
                .FirstOrDefault();

Console.WriteLine(testId);

效果也一样;使用您认为最容易使用的任何形式。

答案 1 :(得分:1)

您可以尝试让System.Xml.Linq为您完成更多工作。这样的事情可能会更简单。

class DayCollectionViewCell: UICollectionViewCell {

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    func clearArrow(){
        self.layer.sublayers = nil
    }

    func drawArrow(){

        let start_x = self.bounds.minX
        let start_y = self.bounds.minY

        let top_width = self.bounds.width
        let tick_height = self.bounds.height
        let tip_height = CGFloat(10)
        let tip_flare = CGFloat(6)
        let arrowLayer = CAShapeLayer()
        let path = UIBezierPath()
        path.move(to: CGPoint(x: start_x, y: start_y + tick_height))
        path.addLine(to: CGPoint(x: start_x + top_width,y: start_y + tick_height))
        path.addLine(to: CGPoint(x: start_x + top_width + tip_flare,y: start_y+tick_height+tip_height))
        path.addLine(to: CGPoint(x: start_x - tip_flare,y: start_y + tick_height + tip_height))
        path.close()
        arrowLayer.path = path.cgPath
        arrowLayer.fillColor = UIColor(red:0.99, green:0.13, blue:0.25, alpha:1.0).cgColor
        self.layer.addSublayer(arrowLayer)
    }
    override var isSelected: Bool{
        didSet{
            if self.isSelected
            {
               self.drawArrow()
            }
            else
            {
                self.clearArrow()
            }
        }
    }


}

enter image description here

答案 2 :(得分:1)

您想在Element的子级上使用Elements而不是TestIdentification并合并过滤器。

var testObj = (from el in xml.DescendantsAndSelf().Elements("TestIdentification")
               where el.Element("TestType").Value == "TESTID2" && !string.IsNullOrWhiteSpace(el.Element("TestID")?.Value)
               select new TestClassObj { TestID = el.Element("TestID").Value })
               .FirstOrDefault();

Console.WriteLine(testObj.TestID); // 106492