C #: Как я могу отфильтровать результаты файла XML на основе атрибута дочернего элемента? - PullRequest
3 голосов
/ 05 марта 2019

Возможно, я мог бы лучше сформулировать название, но я углубляюсь в те области программирования, в которых никогда раньше не был, поэтому я все еще изучаю терминологию. Но вот что я пытаюсь сделать:

Я пишу программу, которая может выполнять структурный анализ болтовых соединений. Однако вместо того, чтобы пользователь вводил геометрию болта каждый раз, я бы хотел дать ему возможность выбирать из стандартного списка размеров ASME Unified Thread Standard (UTS). Итак, я создал класс Bolt, а затем подкласс UTSBolt. И я делаю XML-файл для размеров болтов UTS. И до сих пор я могу десериализовать XML-файл, спроецировать его на IEnumerable моего класса UTSBolts, позволить пользователю выбрать болт, и все будет в порядке.

Но вот моя проблема ...

Размеры 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). Но я не могу понять, как правильно установить фильтры для чтения только в ThreadDensity, где атрибут Series - «UNF». Моя программа всегда получает первое значение 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

1 Ответ

3 голосов
/ 05 марта 2019

Вы смотрите только на атрибут Series в этом подзапросе :

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

Это просто проверяет, есть ли любой ThreadDensity элемент в el имеет правильный ряд.

Код, в котором вы на самом деле создаете UTSBolt просто получает первый ThreadDensity элемент:

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

Iподозреваю, что вы хотите что-то вроде:

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