Linq для объединения таблиц на XElement.Name = XAttribute ("n") - PullRequest
0 голосов
/ 14 декабря 2010

Это сводит меня с ума от бат-гуано! Файл данных клиента:

<rows>
    <row>
        <CustomerID>ABC123</CustomerID>
        <PrdcrCd>10</PrdcrCd>
        <StrAdr>123 Main St., NW</StrAdr>
        <City>Anytown</City>
        etc.
    </row>
<rows>

Файл карты для преобразования данных клиента в приемлемый ввод:

<SourceEntries>
    <map>
        <Field n='CustomerID' m='201' />
        <Field n='StrAdr' m='315' />
        <Field n='City' m='316' />
        <Field n='PrdrCd' m='442' />
        etc.
    </map>
</SourceEntries>

Наконец, шаблон для допустимого ввода:

<template>
    <Field n='ClientId' id='201' />
    <Field n='Street Address' id='315' />
    <Field n='City' id='316' />
    <Field n='ProducerCode' id='442' />
    etc.
</template>

Итак, из имени XElement файла клиента сопоставьте значение атрибута «Исходные записи» «n» и получите ссылку на карту «Исходные данные» m. Затем используйте m для сопоставления атрибута элемента шаблона i, извлеките атрибут имени шаблона 'n' и создайте новое дерево XElement, используя это имя.

Поскольку я новичок в Linq и не особо разбираюсь в XML, я решил начать медленно. Как это:

var results = from t1 in clientXm.Elements("row").Descendants()
      join t2 in sourceEntries.Elements("Field") on t1.Name equals t2.Attributes("n") into xRef
      select new
          {
              (string)xRef.Attributes("n"),
              (string)xRef.Attributes("m")
          };

Первая ошибка в предложении соединения в "on t1.Name.LocalName equals" заключается в том, что тип аргумента 'string' не может быть назначен параметру типа 'TKey'. Затем в предложении select для двух интересующих меня элементов я получаю «Инициализатор проекции анонимного типа должен быть простым именем или выражением доступа к члену». Да, и, конечно, файловые структуры XML являются требованиями спецификации, поэтому я не могу изменить ни одну из них.

В этот момент я так смущен, что не знаю, перевернут ли мир, или я стою на голове. Могу ли я купить ключ ... или хотя бы гласную? Любая помощь очень ценится.

РЕДАКТИРОВАТЬ

Используя LinqPad, я попробовал следующее утверждение:

XElement _clientXml = XElement.Load(@"client.xml");
XElement _sourceEntries = XElement.Load(@"Client_Map.xml");

foreach (XElement clientData in _clientXml.Descendants("row").Descendants()){
    IEnumerable<XElement> mapRefs =
        from mapData in _sourceEntries.Descendants("Field")
        where clientData.Name.LocalName == (string) mapData.Attribute("n")
        select mapData;
    foreach (XElement item in mapRefs){
        Console.WriteLine(item.Attribute("m"));
    }   
}

В LinqPad это произвело список значений "m" - именно то, что я пытаюсь получить на этом шаге ребенка. НО точно такой же код в VS мне ничего не дает. Когда я отлаживаю, mapRefs - пустой набор, когда я добираюсь до второго foreach.

Имеет ли это какой-либо смысл?

Спасибо Randy

Ответы [ 2 ]

1 голос
/ 14 декабря 2010

Некоторые из ваших входов не совсем правильно выровнены. Вот хорошая отправная точка:

var rowText = 
@"<rows>
    <row>
        <CustomerID>ABC123</CustomerID>
        <PrdrCd>10</PrdrCd>
        <StrAdr>123 Main St., NW</StrAdr>
        <City>Anytown</City>
        etc.
    </row>
</rows>";
var sourceEntriesText =
@"<SourceEntries>
    <map>
        <Field n='CustomerID' m='201' />
        <Field n='StrAdr' m='315' />
        <Field n='City' m='316' />
        <Field n='PrdrCd' m='442' />
        etc.
    </map>
</SourceEntries>";
var templateText =
@"<template>
    <Field n='ClientId' id='201' />
    <Field n='Street Address' id='315' />
    <Field n='City' id='316' />
    <Field n='ProducerCode' id='442' />
    etc.
</template>";
var clientXm = XDocument.Parse(rowText);
var sourceEntries = XDocument.Parse(sourceEntriesText);
var results = from r in clientXm.Descendants("row")
            from t1 in r.Elements()
            let xRef = sourceEntries.Descendants("Field").FirstOrDefault(
                        t2 => t1.Name == t2.Attribute("n").Value)
            select new
                {
                    t1,
                    xRef
                };

Немного больше работы дает что-то, вероятно, ближе к тому, что вы ищете:

var results = from r in clientXm.Descendants("row")
            from t1 in r.Elements()
            join t2 in sourceEntries.Descendants("Field")
            on t1.Name equals t2.Attribute("n").Value
            join t3 in template.Descendants("Field")
            on t2.Attribute("m").Value equals t3.Attribute("id").Value
            select new
                {
                    Name = t3.Attribute("n").Value,
                    Value = t1.Value,
                };
0 голосов
/ 14 декабря 2010

Ну, это легко исправить ошибки компилятора:

var results = from t1 in clientXm.Elements("row").Descendants()
              join t2 in sourceEntries.Elements("Field")
              on t1.Name.LocalName equals (string) t2.Attribute("n") into xRef
              select new
              {
                  N = (string)xRef.Attributes("n"),
                  M = (string)xRef.Attributes("m")
              };

Однако я не уверен, как вы собираетесь использовать приведение от IEnumerable<XAttribute> до string в проекции ...

Я подозреваю, что вы не хотите присоединиться к группе (это то, что вы получаете с объединением ... в. Но я не понимаю, как работает ваш образец данных, поэтому трудно дать вам правильный код. Откуда, например, ClientId может появиться? Вы получили его только в своем примере output ... при условии, что это ваш пример вывода, конечно.

По сути, если бы вы могли упростить свои выборочные данные на два входа и выход и объяснить, как вывод получен, это облегчило бы жизнь ... на данный момент неясно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...