简体   繁体   English

C#:如何根据子元素的属性过滤XML文件的结果?

[英]C#: How can I filter the results of an XML file based on a child element's attribute?

I probably could have worded the title better, but I'm venturing into areas of programming that I've never been to before, so I'm still learning the terminology. 我可能会更好地说出这个标题,但是我正在冒险进入以前从未去过的编程领域,所以我还在学习术语。 But here's what I'm trying to do: 但这就是我要做的事情:

I'm writing a program that can perform structural analyses on bolted joints. 我正在编写一个可以对螺栓连接进行结构分析的程序。 However, rather than have the user enter the bolt geometry every single time, I'd like to give them an option to select from a standard list of ASME Unified Thread Standard (UTS) sizes. 但是,我不想让用户每次都输入螺栓几何体,而是让他们选择从ASME统一线程标准(UTS)尺寸的标准列表中进行选择。 So I've created a Bolt class and then a UTSBolt subclass. 所以我创建了一个Bolt类,然后创建了一个UTSBolt子类。 And I'm making an XML file for UTS bolt sizes. 我正在为UTS螺栓尺寸制作一个XML文件。 And so far, I can de-serialize the XML file, project it to an IEnumerable of my UTSBolts class, let the user select a bolt, and everything is hunky-dory. 到目前为止,我可以对XML文件进行反序列化,将其投影到我的UTSBolts类的IEnumerable中,让用户选择一个螺栓,一切都是hunky-dory。

But here's my problem... 但这是我的问题......

UTS sizes will specify a bolt's diameter as well as it's thread density for both a coarse-thread (UNC) and a fine-thread (UNF) bolt. UTS尺寸将指定螺纹直径以及粗螺纹(UNC)和细螺纹(UNF)螺栓的螺纹密度。 As such, I've formatted my XML file like this: 因此,我已经格式化了我的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>

When the user selects a bolt size, I'd like them to be able to select a thread series (UNC/UNF) as well. 当用户选择螺栓尺寸时,我希望它们也能够选择螺纹系列(UNC / UNF)。 But I can't seem to figure out how to properly set the filters to read in only ThreadDensity where the Series attribute is "UNF". 但我似乎无法弄清楚如何正确设置过滤器只读取ThreadDensity,其中Series属性为“UNF”。 My program always grabs the first ThreadDensity value, regardless of the attribute. 无论属性如何,我的程序总是抓取第一个ThreadDensity值。

Can somebody please help me figure out what I'm doing wrong? 有人可以帮我弄清楚我做错了什么吗? Here's my code: 这是我的代码:

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();
    }

Output: 输出:

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

You're only looking at the Series attribute in this subquery : 您只查看此子查询中的Series属性:

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

That just checks whether any ThreadDensity element within el has the right series. 这只是检查el中的任何 ThreadDensity元素是否具有正确的系列。

The code where you're actually creating the UTSBolt just gets the first ThreadDensity element: 您实际创建 UTSBolt的代码只获取第一个ThreadDensity元素:

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

I suspect you want something like: 我怀疑你想要的东西:

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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM