【问题标题】:C#: How can I filter the results of an XML file based on a child element's attribute?C#:如何根据子元素的属性过滤 XML 文件的结果?
【发布时间】:2019-03-05 15:29:13
【问题描述】:

我可能可以更好地措辞标题,但我正在冒险进入我以前从未涉足的编程领域,所以我仍在学习术语。但这是我想要做的:

我正在编写一个可以对螺栓连接进行结构分析的程序。但是,与其让用户每次都输入螺栓几何形状,我想给他们一个选项,让他们从 ASME 统一螺纹标准 (UTS) 尺寸的标准列表中进行选择。所以我创建了一个 Bolt 类,然后创建了一个 UTSBolt 子类。我正在为 UTS 螺栓尺寸制作一个 XML 文件。到目前为止,我可以反序列化 XML 文件,将其投影到我的 UTSBolts 类的 IEnumerable 中,让用户选择一个螺栓,一切都很好。

但这是我的问题...

UTS 尺寸将指定螺栓的直径以及粗螺纹 (UNC) 和细螺纹 (UNF) 螺栓的螺纹密度。因此,我的 XML 文件格式如下:

<Bolts_UTS>
  <Bolt>
    <Size>#0</Size>
    <MajorDiameter>0.0600</MajorDiameter>
    <ThreadDensity Series="UNF">80</ThreadDensity>
  </Bolt>
  <Bolt>
    <Size>#1</Size>
    <MajorDiameter>0.0730</MajorDiameter>
    <ThreadDensity Series="UNC">64</ThreadDensity>
    <ThreadDensity Series="UNF">72</ThreadDensity>
  </Bolt>
  <Bolt>
    <Size>#2</Size>
    <MajorDiameter>0.0860</MajorDiameter>
    <ThreadDensity Series="UNC">56</ThreadDensity>
    <ThreadDensity Series="UNF">64</ThreadDensity>
  </Bolt>
  <Bolt>
    <Size>#3</Size>
    <MajorDiameter>0.0990</MajorDiameter>
    <ThreadDensity Series="UNC">48</ThreadDensity>
    <ThreadDensity Series="UNF">56</ThreadDensity>
  </Bolt>
  <Bolt>
    <Size>#4</Size>
    <MajorDiameter>0.1120</MajorDiameter>
    <ThreadDensity Series="UNC">40</ThreadDensity>
    <ThreadDensity Series="UNF">48</ThreadDensity>
  </Bolt>
</Bolts_UTS>

当用户选择螺栓尺寸时,我希望他们也能够选择螺纹系列 (UNC/UNF)。但我似乎无法弄清楚如何正确设置过滤器以仅读取 Series 属性为“UNF”的 ThreadDensity。我的程序总是获取第一个 ThreadDensity 值,而不管属性如何。

有人可以帮我弄清楚我做错了什么吗?这是我的代码:

static void Main(string[] args)
    {
        string pathCurrent = Directory.GetCurrentDirectory();
        string pathToXML = Path.GetFullPath(Path.Combine(pathCurrent, "Bolts_UTS.xml"));

        XElement boltsUTS = XElement.Load(pathToXML);
        IEnumerable<UTSBolt> boltList =
            from el in boltsUTS.Elements("Bolt")
            where (
                from thread in el.Elements("ThreadDensity")
                where
                    (string)thread.Attribute("Series") == "UNF"
                select thread).Any() &&
                ((string)el.Element("Size") == "#1")
            select new UTSBolt(
                (string)el.Element("Size"),
                (double)el.Element("MajorDiameter"),
                (double)el.Element("ThreadDensity")
            );
        Console.WriteLine("        |    Major    |");
        Console.WriteLine("UN Size\t| Dia. (inch) | Thr. / In.");
        Console.WriteLine("--------|-------------|------------");
        foreach (UTSBolt bolt in boltList)
            Console.WriteLine(bolt);

        Console.ReadLine();
    }

输出:

        |    Major    |
UN Size | Dia. (inch) | Thr. / In.
--------|-------------|------------
#1      |   0.07300   |     64

【问题讨论】:

    标签: c# xml linq ienumerable


    【解决方案1】:

    您只在此子查询中查看Series 属性:

     where (
        from thread in el.Elements("ThreadDensity")
        where
            (string)thread.Attribute("Series") == "UNF"
        select thread).Any() &&
        ((string)el.Element("Size") == "#1")
    

    这只是检查el 中的任何 ThreadDensity 元素是否具有正确的系列。

    您实际创建 UTSBolt 的代码只是获取第一个 ThreadDensity 元素:

    select new UTSBolt(
        (string)el.Element("Size"),
        (double)el.Element("MajorDiameter"),
        (double)el.Element("ThreadDensity")
    );
    

    我怀疑你想要类似的东西:

    var boltList =
        from el in boltsUTS.Elements("Bolt")
        let thread = el.Elements("ThreadDensity")
                       .FirstOrDefault(t => (string) t.Attribute("Series") == "UNF")
        let size = (string) el.Element("Size")
        where thread != null && size == "#1"
        select new UTSBolt(size, (double) el.Element("MajorDiameter"), (double) thread);
    

    【讨论】:

    • 杰出 - 做到了!太感谢了!我非常感谢您解释为什么我以前的代码不起作用。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多