Как выполнить итерацию по узлам XElement в XDocument и добавить в другой элемент XElement?

У меня есть XML-документ, который выглядит так:

<Person>
  <LastName>LastName1</LastName>
  <FirstName>FirstName1</FirstName>
  <MiddleName>MiddleName1</MiddleName>
</Person>

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

public XElement ToXML()
{
  return new XElement("Person",
    new XElement(this.LastName.ToXML()),
    new XElement(this.FirstName.ToXML()),
    new XElement(this.MiddleName.ToXML()));
}

Проблема в том, что помимо Person существует множество других узлов, которые используют значения Name в корне. Итак, что я пытался сделать, так это реорганизовать элементы FirstName, LastName и MiddleName, чтобы они находились в их собственном повторно используемом классе с методом ToXMLDoc(), который возвращает эти элементы как XDocument вместо XElement (поскольку корень будет продиктован классом, нуждающимся в имя детей; может быть Person, Employee и т. д.)

Вот что возвращает мой новый ToXMLDoc:

return new XDocument(new XElement(this.LastName.ToXML()),
                     new XElement(this.FirstName.ToXML()),
                     new XElement(this.MiddleName.ToXML()));

Моя проблема в том, что я хочу теперь добавить этот контент в внутри корня XElement, добавленного моим классом Person. Я попытался сделать что-то вроде приведенного ниже, но неправильно использую конструктор и получаю сообщение об ошибке "Неоднозначная ссылка на конструктор".

return new XElement("Person",
    foreach (XElement xe in NameType.ToXMLDoc().Nodes())
    {
      new XElement(xe.Value);
    }
);

Как я могу взять содержимое из метода ToXMLDoc() и добавить его в узел XElement, создаваемый для Person? Любая помощь приветствуется, спасибо!


person atconway    schedule 04.02.2013    source источник
comment
Какой тип свойств LastName, FirstName и MiddleName? А что делает метод ToXML()?   -  person Sergey Berezovskiy    schedule 04.02.2013


Ответы (2)


В настоящее время вы пытаетесь внедрить цикл foreach внутри вызова конструктора. Это не сработает, но на самом деле это довольно просто:

return new XElement("Person", NameType.ToXMLDoc()
                                      .Nodes()
                                      .Select(xe => new XElement(xe.Value));

Вы уверены, что не хотите просто копировать элементы целиком? В этом случае это будет просто:

return new XElement("Person", NameType.ToXMLDoc().Nodes());
person Jon Skeet    schedule 04.02.2013
comment
Было ли использование XDocument для хранения (3) отдельных узлов имени в методе ToXMLDoc подходящим типом, или вместо этого вы использовали бы что-то другое, например List<XElement>? - person atconway; 04.02.2013
comment
@atconway: Честно говоря, неясно, чего вы пытаетесь достичь. Если все, что вам нужно, это три имени, почему вы не используете вместо них List<string>? - person Jon Skeet; 04.02.2013
comment
Я создаю отдельные классы, которые при составлении могут создавать XDocuments для отправки сообщений. Существует множество различных сообщений, поэтому классы должны оставаться гибкими, и все они должны использовать типы XElement (составные дочерние элементы) и XDocument (основное сообщение, выполняющее композицию). Этот класс, содержащий отдельные элементы NameType, должен возвращать эти значения XElement, а затем использоваться классами 1..n, которые будут определять его корневое значение. Ваше решение для того, как оно у меня сейчас, с использованием XDocument работает, но интересно, предпочтительнее ли использовать List<XElement>? Тогда мне нужно это решение. - person atconway; 04.02.2013
comment
@atconway: Извините, вы предоставили много мелких деталей, но недостаточно контекста, чтобы действительно понять вашу систему. Если то, что я дал, работает для вас, то я бы пошел с этим. Вы можете легко создать List<XElement>, если захотите позже. - person Jon Skeet; 04.02.2013
comment
Кстати, делать это оптом, как вы спрашивали, было так, как я хотел (не знал, что это можно сделать так), но другой метод приятно знать. Спасибо за помощь. - person atconway; 04.02.2013

Я бы вернул XElement, а не XDocument

Таким образом, вы можете просто сделать:

new XElement("Person", NameType.ToXMLDoc())
person paul    schedule 04.02.2013
comment
Как я могу вернуть тип XElement, если у меня нет корня, а есть набор корневых узлов? (т.е. это только LastName, FirstName, MiddelName без корневого элемента). Я перешел к XDocument, который мог содержать все отдельные узлы. - person atconway; 04.02.2013
comment
Да вы правы. Я бы, наверное, вернул что-то вроде ‹name›‹firstname›‹middleName›‹lastname›‹/name› - person paul; 04.02.2013
comment
Да, единственное, что тогда мне всегда нужно помнить, чтобы удалить этот корень <name>, потому что он должен быть <person> или чем-то еще, как продиктовано вызывающим классом, которому нужны дочерние узлы имени. - person atconway; 04.02.2013
comment
Мне просто не нравится создавать несовместимые XDocuments. Может быть, тогда я бы выбрал List<XElement> или что-то в этом роде. Метод, предложенный Jon S, абсолютно хорош. - person paul; 04.02.2013