Where condition with linq dynamic built at runtime to read xml

Where condition with linq dynamic built at runtime to read xml

我在使用 linq(lambda 表达式)查询读取软件中嵌入的复杂大型 xml 文件时遇到问题。在post的底部可以找到单个字段"PRODOTTO"的结构,但是在xml.

中有大约2800个这样的条目

问题出在where条件上。我需要动态添加更多条件(取决于用户交互)。

我尝试使用 System.Linq.Dynamic

我需要 select 所有具有名为 "CAPITOLO" 和 "GR_MERC" 字段的产品,只有一个 select 由用户(之前)编辑并具有特定值。 "CAPITOLO" 的值为 1,2,3,4,5,6,7,8,9,10,11,12,99(13 种类型),"GR_MERC" 的值为 1,2, 3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27, 32,82,88,89(31种) 用户可以 select 一个字段和 select 编辑字段的一个或多个值。 我需要在运行时构建 where 子句。

这是不起作用的代码片段。

using System.Linq.Dynamic;

var query = XElement.Parse(Properties.Resources.CATALOGO).Elements("PRODOTTO");

// Start of where part
string clauses = string.Empty;  //String for the clauses
int n_clauses = cat.Count();  //Count the number of clauses
int counter = 0;
if (TypeOfFilter == 0)  //TypeOfView = 0 Show the product to user by CAPITOLO (he select type of filter before)
{
    foreach (var p in cat)  //Can be only one "CAPITOLO" condition or maximum 13
    {
        clauses += string.Format("\"CAPITOLO\" == \"{0}\"", p);  //<-- here is the problem. Return always 0 results.
        counter++;
        if (counter < n_clauses)
            clauses += " || ";  //Add the OR condition
    }
}
else //TypeOfView = 1 Show the product to user by GR_MERC (he select type of filter before)
{
    foreach (var p in cat)  //Can be only one "GR_MERC" condition or maximum 31
    {
        clauses += string.Format("\"GR_MERC\" == \"{0}\"", p);  //<-- here is the problem. Return always 0 results.
        counter++;
        if (counter < n_clauses)
            clauses += " || ";  //Add the OR condition
    }
}
query = query.Where(clauses).ToList();
// End of where part

如果我排除 "where" 部分,最后一部分效果很好。

var query2 = query
            .GroupBy(x => x.Element("CODICE"))
            .Select(x => new
            {
                ARTICOLO = x.Elements("ARTICOLO").First().Value,
                CODICE = x.Elements("CODICE").First().Value,
                DESCRIZIONE = x.Elements(language).First().Value, //Can be one of IT, EN, DE, FR, RU, RO, ZH selected before from the user
                MISURA = x.Elements("MISURA").First().Value,
                PREZZO = decimal.Parse(x.Elements("PREZZO").First().Value),
                SC1 = decimal.Parse(x.Elements("SC_BASE").First().Value),
                SC2 = decimal.Parse(x.Elements(sc).First().Value),  //One value between SC_IT and SC_ES
                CAPITOLO = int.Parse(x.Elements("CAPITOLO").First().Value),
                PAGINA = int.Parse(x.Elements("PAGINA").First().Value),
                RIQUADRO = int.Parse(x.Elements("RIQUADRO").First().Value),
                SUBORD = int.Parse(x.Elements("SUBORD").First().Value)
            })
            .ToList()
            .OrderBy(b => b.CAPITOLO).ThenBy(b => b.PAGINA).ThenBy(b => b.RIQUADRO).ThenBy(b => b.SUBORD)
            .Select(x => new Article
            {
                Art = x.ARTICOLO,
                Cod = x.CODICE,
                Des = x.DESCRIZIONE,
                Mis = x.MISURA,
                Prz = x.PREZZO,
                Sc1 = x.SC1,
                Sc2 = x.SC2
            });

更新了 XML

的结构

xml文件的结构是这样的(只有2个产品,大约2800个):

<DATA xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <PRODOTTO>
        <PRODOTTO_ID>2540</PRODOTTO_ID>
        <ARTICOLO>208CTP</ARTICOLO>
        <CODICE>208CTP-06-04</CODICE>
        <CAPITOLO>99</CAPITOLO>
        <PAGINA>41</PAGINA>
        <RIQUADRO>1</RIQUADRO>
        <SUBORD>4</SUBORD>
        <MISURA>1”x4</MISURA>
        <PREZZO>51.80</PREZZO>
        <SC_BASE>0.51</SC_BASE>
        <SC_IT>0.10</SC_IT>
        <SC_ES>0.10</SC_ES>
        <QUANTITA>1</QUANTITA>
        <CONFEZIONE>5</CONFEZIONE>
        <GR_MERC>20</GR_MERC>
        <UM>N°</UM>
        <IT>Collettore di andata F.F. con attacchi derivati 3/4”M Eurocono, regolatori e misuratori di portata. Interasse 50 mm.</IT>
        <EN>F.F. delivery manifold with 3/4”M Eurocone connections and flow regulators and meters. Centre distance 50 mm.</EN>
        <DE>Vorlaufverteiler IG/IG, Anschluss 3/4”AG Eurokonus, mit Durchflussmessern. Achsabstand 50 mm.</DE>
        <RU>Коллектор подачи (внутр.-внутр. резьба) со штуцерами для отводов на 3/4” (наружн. резьба) «евроконус», регуляторами и расходомерами. Межосевое расстояние 50мм</RU>
        <FR>Collecteur de départ F.F. avec raccords dérivés 3/4”M Eurocone et débitmètres. Entraxe 50 mm.</FR>
        <RO> Tur colector cu FI.FI din inoxcu conexiuni 3/4” FE Eurocon echipat cu supape de inchidere cu debitmetre cu scala. Distanţa interaxiala 50 mm.</RO>
        <ZH>带流量计分水器</ZH>
        <CATEGORIA_IT>FUORI LISTINO</CATEGORIA_IT>
        <CATEGORIA_EN>OTC</CATEGORIA_EN>
        <CATEGORIA_DE>OTC</CATEGORIA_DE>
        <CATEGORIA_RU>OTC</CATEGORIA_RU>
        <CATEGORIA_FR>OTC</CATEGORIA_FR>
        <CATEGORIA_RO>OTC</CATEGORIA_RO>
        <CATEGORIA_ZH>OTC</CATEGORIA_ZH>
        <SOTTOCATEGORIA_EN xsi:nil="true" />
        <SOTTOCATEGORIA_DE xsi:nil="true" />
        <SOTTOCATEGORIA_RU xsi:nil="true" />
        <SOTTOCATEGORIA_FR xsi:nil="true" />
        <SOTTOCATEGORIA_RO xsi:nil="true" />
        <SOTTOCATEGORIA_ZH xsi:nil="true" />
        <GR_MERC_DESCR_IT>COLLETTORI DI DISTRIBUZIONE IN OTTONE CROMATO</GR_MERC_DESCR_IT>
        <GR_MERC_DESCR_EN>BRASS CHROME DISTRIBUTION MANIFOLDS</GR_MERC_DESCR_EN>
        <GR_MERC_DESCR_DE>VERTEILER AUS MESSING CHROMIERT</GR_MERC_DESCR_DE>
        <GR_MERC_DESCR_RU>ХРОМИРОВАННЫЕ КОЛЛЕКТОРЫ ИЗ ЛАТУНИ</GR_MERC_DESCR_RU>
        <GR_MERC_DESCR_FR>COLLECTEURS DE DISTRIBUTION EN LAITON CHROMÉ</GR_MERC_DESCR_FR>
        <GR_MERC_DESCR_RO xsi:nil="true" />
        <GR_MERC_DESCR_ZH xsi:nil="true" />
        <L14_2016 xsi:nil="true" />
        <AUMENTO_14_15 xsi:nil="true" />
    </PRODOTTO>
    <PRODOTTO>
        <PRODOTTO_ID>2432</PRODOTTO_ID>
        <ARTICOLO>286HT</ARTICOLO>
        <CODICE>286HT-053B</CODICE>
        <CAPITOLO>8</CAPITOLO>
        <PAGINA>40</PAGINA>
        <RIQUADRO>2</RIQUADRO>
        <SUBORD>1</SUBORD>
        <MISURA>3/4”x3/8”</MISURA>
        <PREZZO>8.15</PREZZO>
        <SC_BASE>0.51</SC_BASE>
        <SC_IT>0.10</SC_IT>
        <SC_ES>0.10</SC_ES>
        <QUANTITA>1</QUANTITA>
        <CONFEZIONE xsi:nil="true" />
        <GR_MERC>3</GR_MERC>
        <UM>N°</UM>
        <IT>Calotta con codolo e O-Ring di battuta per valvole Design.</IT>
        <EN>Union connection with O-Ring seal for Design valves.</EN>
        <DE>Überwurfmutter mit Rohrstutzen und O-Ring für Design Ventile.</DE>
        <RU>Гайка с хвостовиком и упорным уплотнительным кольцом O-Ring</RU>
        <FR>Ecrou avec douille et joint torique pour robinets Design.</FR>
        <RO>Conexiune cu O-ring pentru robineti Design.</RO>
        <ZH xsi:nil="true" />
        <CATEGORIA_IT>VALVOLE E DETENTORI</CATEGORIA_IT>
        <CATEGORIA_EN>VALVES AND LOCKSHIELDS</CATEGORIA_EN>
        <CATEGORIA_DE>VENTILE UND RÜCKLAUFVENTILE</CATEGORIA_DE>
        <CATEGORIA_RU>КЛАПАНЫ И ЗАПОРНЫЕ ВЕНТИЛИ</CATEGORIA_RU>
        <CATEGORIA_FR>ROBINETS ET TÉS DE RÉGLAGE</CATEGORIA_FR>
        <CATEGORIA_RO>ROBINETE TUR RETUR</CATEGORIA_RO>
        <CATEGORIA_ZH>锁闭阀和温控阀</CATEGORIA_ZH>
        <SOTTOCATEGORIA_IT>VALVOLE DESIGN</SOTTOCATEGORIA_IT>
        <SOTTOCATEGORIA_EN>DESIGN VALVES</SOTTOCATEGORIA_EN>
        <SOTTOCATEGORIA_DE>DESIGN VENTILE</SOTTOCATEGORIA_DE>
        <SOTTOCATEGORIA_RU>ДИЗАЙНЕРСКИЕ ВЕНТИЛИ</SOTTOCATEGORIA_RU>
        <SOTTOCATEGORIA_FR>ROBINETS DESIGN</SOTTOCATEGORIA_FR>
        <SOTTOCATEGORIA_RO>ROBINETE DESIGN</SOTTOCATEGORIA_RO>
        <SOTTOCATEGORIA_ZH xsi:nil="true" />
        <GR_MERC_DESCR_IT>RACCORDI PER VALVOLE HI-TECH</GR_MERC_DESCR_IT>
        <GR_MERC_DESCR_EN>DESIGN FITTINGS</GR_MERC_DESCR_EN>
        <GR_MERC_DESCR_DE>DESIGN ANSCHLUSSSTÜCKE</GR_MERC_DESCR_DE>
        <GR_MERC_DESCR_RU>ФИТИНГИ ДИЗАЙНА</GR_MERC_DESCR_RU>
        <GR_MERC_DESCR_FR>RACCORDS HIGH-TECH</GR_MERC_DESCR_FR>
        <GR_MERC_DESCR_RO xsi:nil="true" />
        <GR_MERC_DESCR_ZH xsi:nil="true" />
        <L14_2016 xsi:nil="true" />
        <AUMENTO_14_15 xsi:nil="true" />
    </PRODOTTO>
</DATA>

使用字典和 Xml Linq :

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

namespace ConsoleApp2
{

    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main()
        {
            XDocument doc = XDocument.Load(FILENAME);

            List<XElement> PRODOTTO = doc.Descendants().Where(x => x.Name.LocalName == "PRODOTTO").Select(x => x.Elements()).SelectMany(x => x).ToList();

            Dictionary<string, string> products = PRODOTTO
                .GroupBy(x => x.Name.LocalName, y => (string)y)
                .ToDictionary(x => x.Key, y => y.FirstOrDefault());

            //use following if more than one item with same tag
            Dictionary<string, List<string>> products2 = PRODOTTO
              .GroupBy(x => x.Name.LocalName, y => (string)y)
              .ToDictionary(x => x.Key, y => y.ToList());

            Dictionary<string, Dictionary<string,string>> products3 = doc.Descendants().Where(x => x.Name.LocalName == "PRODOTTO")
                .GroupBy(x => (string)x.Element("PRODOTTO_ID"), y => y.Elements()
                    .GroupBy(a => a.Name.LocalName, b => (string)b)
                    .ToDictionary(a => a.Key, b => b.FirstOrDefault()))
                    .ToDictionary(x => x.Key, y => y.FirstOrDefault());
        }
    }
}