将XmlNodeList的内容转换为新的XmlDocument而不进行循环

时间:2015-06-22 08:47:32

标签: c# xml xpath xmldocument xmlnodelist

我有使用XPath过滤的Xml(类似于此的查询):

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace TestCancellation
{
    class Program
    {
        static void Main(string[] args)
        {
            ItWorksWellAndThrowsException();
            //ItShouldThrowAExceptionButStallsInstead();
        }

        private static void ItShouldThrowAExceptionButStallsInstead()
        {
            Task.Run(async () =>
            {
                var coordinator = new CancellationHelper();
                var waitHandle = new ManualResetEvent(false);

                var task = Task.Run(() =>
                {
                    waitHandle.WaitOne();

                    //this works well though - it throws
                    //coordinator.ThrowIfCancellationRequested();

                }, coordinator.Token);

                await coordinator.CancelAsync();
                //waitHandle.Set(); -- with or without this it will throw
                task.Wait();
            }).Wait();
        }

        private static void ItWorksWellAndThrowsException()
        {
            Task.Run(() =>
            {
                var coordinator = new CancellationHelper();
                var waitHandle = new ManualResetEvent(false);

                var task = Task.Run(() => { waitHandle.WaitOne(); }, coordinator.Token);

                coordinator.Cancel();
                task.Wait();
            }).Wait();
        }
    }

    public class CancellationHelper
    {
        private CancellationTokenSource cancellationTokenSource;
        private readonly List<Task> tasksToAwait;

        public CancellationHelper()
        {
            cancellationTokenSource = new CancellationTokenSource();
            tasksToAwait = new List<Task>();
        }

        public CancellationToken Token
        {
            get { return cancellationTokenSource.Token; }
        }

        public void AwaitOnCancellation(Task task)
        {
            if (task == null) return;

            tasksToAwait.Add(task);
        }

        public void Reset()
        {
            tasksToAwait.Clear();
            cancellationTokenSource = new CancellationTokenSource();
        }

        public void ThrowIfCancellationRequested()
        {
            cancellationTokenSource.Token.ThrowIfCancellationRequested();
        }

        public void Cancel()
        {
            cancellationTokenSource.Cancel();

            Task.WaitAll(tasksToAwait.ToArray());
        }

        public async Task CancelAsync()
        {
            cancellationTokenSource.Cancel();

            try
            {
                await Task.WhenAll(tasksToAwait.ToArray());
            }
            catch (AggregateException ex)
            {
                ex.Handle(p => p is OperationCanceledException);
            }
        }
    }
}

这会过滤掉原始Persons Xml中的所有重复项。我想从上面生成的XmlNodeList创建一个新的XmlDocument实例。在那一刻,我能看到的唯一方法是循环遍历XmlNode列表并构建一个Xml字符串(如此):

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

必须有一种更有效的方法吗?

2 个答案:

答案 0 :(得分:1)

如果您乐意将其转换为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那样简单:)

答案 1 :(得分:1)

使用XmlDocument,您可以使用

XmlDocument doc2 = new XmlDocument();
doc2.AppendChild(doc2.CreateElement("Persons"));
foreach (XmlElement person in allItems)
{
  doc2.DocumentElement.AppendChild(doc2.ImportNode(person, true));
}