Преобразование содержимого XmlNodeList в новый XmlDocument без зацикливания

У меня есть Xml, который я фильтрую с помощью XPath (запрос, подобный этому):

    XmlNodeList allItems = 
xDoc.SelectNodes("//Person[not(PersonID = following::Person/PersonID)]");

Это отфильтровывает все дубликаты из моего исходного файла Persons Xml. Я хочу создать новый экземпляр XmlDocument из списка XmlNodeList, сгенерированного выше. На данный момент единственный способ, которым я могу это сделать, - это перебрать список XmlNode и построить строку Xml (как таковую):

        XmlNodeList allItems = xDoc.SelectNodes("//Person[not(PersonID = following::Person/PersonID)]");
        StringBuilder xml = new StringBuilder("<Persons>");

        foreach (XmlNode node in allItems)
            xml.Append(node.OuterXml);

        xml.Append("</Persons>");

        XmlDocument newXDoc = new XmlDocument();
        newXDoc.LoadXml(xml.ToString());

Должен быть более эффективный способ сделать это?


person Rob McCabe    schedule 22.06.2015    source источник
comment
Ради интереса, вам нужно использовать XPath и XmlDocument? LINQ to XML делает такие вещи (и почти все, на самом деле...) проще.   -  person Jon Skeet    schedule 22.06.2015
comment
Я не ценю его загрузку в XmlDocument. На самом деле то, что я использую, предназначено для заполнения DataTable. Так что меня действительно интересует строковый XML. Я преобразовал foreach в Linq, но, похоже, он работает так же медленно, как и foreach выше :-|   -  person Rob McCabe    schedule 22.06.2015


Ответы (2)


Если вы готовы преобразовать его в LINQ to XML, это очень просто:

XDocument original = ...; // However you load the original document
// Separated out for clarity - could be inlined, of course
string xpath = "//Person[not(PersonID = following::Person/PersonID)]"

XDocument people = new XDocument(
    new XElement("Persons",
        original.XPathSelectElements(xpath)
    )
);

Вам определенно не нужно преобразовывать каждый узел в строку и обратно. С XmlDocument это тоже не нужно, но это будет не так просто, как с LINQ to XML :)

person Jon Skeet    schedule 22.06.2015
comment
Получение ошибки при использовании этого подхода Jon Невозможно добавить к содержимому символы, не являющиеся пробелами. Я использую следующий код: string outputXml = null; используя (var nodeReader = new XmlNodeReader(xDoc)) { nodeReader.MoveToContent(); var original = XDocument.Load(nodeReader); string xpath = //Person[not(PersonID = following::Person/PersonID)]; XDocument people = новый XDocument(Persons, original.XPathSelectElements(xpath)); outputXml = люди.ToString(); } - person Rob McCabe; 22.06.2015
comment
ПРИМЕЧАНИЕ: это сработало: XDocument people = new XDocument(new XElement(Persons, original.XPathSelectElements(xpathFilterDups))); - person Rob McCabe; 22.06.2015
comment
@RobMcCabe: Упс, да, забыл сделать корень явным XElement. Фиксированный :) - person Jon Skeet; 22.06.2015

С XmlDocument вы можете использовать

XmlDocument doc2 = new XmlDocument();
doc2.AppendChild(doc2.CreateElement("Persons"));
foreach (XmlElement person in allItems)
{
  doc2.DocumentElement.AppendChild(doc2.ImportNode(person, true));
}
person Martin Honnen    schedule 22.06.2015
comment
Я надеялся избежать повторения каждого XmlElementNode, если это возможно, для повышения эффективности. - person Rob McCabe; 22.06.2015
comment
Я не уверен, как вы предлагаете создать новый документ из элементов в существующем документе, не читая все элементы из существующего документа. Единственная часть этого, которая может быть медленной, - это оценка выражения XPath. - person Charles Mager; 22.06.2015
comment
Это было целью публикации этого вопроса :-), чтобы решить, возможно ли это. Я уже использую подход, аналогичный тому, что вы предложили. XPath на самом деле оценивает достаточно быстро. У меня есть более 4000 элементов для анализа в xml, поэтому цикл for действительно довольно медленный. Надеялся избежать этого :-\ - person Rob McCabe; 22.06.2015
comment
Я не думаю, что есть способ избежать цикла, но использование AppendChild в ImportNode вместо StringBuilder и OuterXml должно быть более эффективным. - person Martin Honnen; 22.06.2015