c# эффективный способ преобразовать список путей в xml - PullRequest
0 голосов
/ 19 февраля 2020

У меня есть список путей к папкам из базы данных, которые мне нужно экспортировать в xml. Необработанные данные выглядят следующим образом:

enter image description here

Мне нужно создать древовидную структуру, подобную этой в xml:

 - networkAdd
    - users
        - test1
           - delete unicode character test
                 - character test 1
                        - linked to folder
                 - character test 2
                 - character test 3
 - sp2013 
    - newTestsite
        - newTestLib
           - sampleFolder
           - Renamed at source again
           - SecurityTest2013Folder
        - Shared Documents
           - sample.folder

В настоящее время у меня есть эффективный метод записи xml, доступный мне, но он требует просмотра дерева. Я взял приведенный выше список (исходящий из базы данных) и преобразовал его в древовидную структуру, которую можно использовать с этим методом (которая работает нормально), но для этого сначала нужно преобразовать в древовидную структуру, что неэффективно. Я использую этот код:

public static TreeView PopulateTreeView(IEnumerable<FolderInfo> paths)
{
    var treeView = new TreeView();
    treeView.PathSeparator = "\\";

    TreeNode lastNode = null;
    string subPathAgg;
    string lastRootFolder = null;

    foreach (var item in paths)
    {
        var path = item.FolderName; // folder path.

        if (lastRootFolder != item.FolderRoot)
        {
            lastRootFolder = item.FolderRoot;
            lastNode = null;
        }

        subPathAgg = string.Empty;
        foreach (string subPath in path.Split('\\'))
        {
            if (subPath.Length > 0)
            {
                subPathAgg += subPath + "\\";
                TreeNode[] nodes = treeView.Nodes.Find(subPathAgg, true);

                var newNode = new TreeNode
                {
                    Name = subPathAgg,
                    Text = subPath,
                    ImageIndex = 2,
                    ToolTipText = item.FullFolderPath
                };

                if (nodes.Length == 0)
                {
                    if (lastNode == null)
                        treeView.Nodes.Add(newNode);
                    else
                        lastNode.Nodes.Add(newNode);

                    lastNode = newNode;
                }
                else
                    lastNode = nodes[0];
            }
        }
    }

    return treeView;
}

Эта строка кода становится очень медленной для выполнения, когда мне нужно обработать более 10 миллионов записей: TreeNode[] nodes = treeView.Nodes.Find(subPathAgg, true);

Это было бы гораздо более эффективным для меня преобразовать напрямую из БД в XML (без посредника в виде дерева).

Кто-нибудь посоветовал альтернативный способ парсинга путей к папкам в xml, принимая во внимание вложенность? Спасибо за любые указатели заранее!

1 Ответ

2 голосов
/ 19 февраля 2020

Оказывается, если вы можете убедиться, что ваши строки правильно отсортированы (что должно быть легко, если они поступают из БД), это довольно легко, если вы работаете напрямую с XmlWriter. Что-то вроде:

var strings = new[]
{
    @"\\networkAdd",
    @"\\networkAdd\users",
    @"\\networkAdd\users\test1\",
    @"\\networkAdd\users\test1\delete unicode character test",
    @"\\networkAdd\users\test1\delete unicode character test\character test 1",
    @"\\networkAdd\users\test1\delete unicode character test\character test 1\linked to folder",
    @"\\networkAdd\users\test1\delete unicode character test\character test 2",
    @"\\networkAdd\users\test1\delete unicode character test\character test 3",
    @"http:\\sp2013",
    @"http:\\sp2013\newTestsite",
    @"http:\\sp2013\newTestlib",
    @"http:\\sp2013\newTestlib\sampleFolder",
};
// Obviously, stream it out to a file rather than an in-memory string
using (var stringWriter = new StringWriter())
using (var writer = new XmlTextWriter(stringWriter))
{
    writer.WriteStartDocument();
    writer.WriteStartElement("Items");

    var previous = Array.Empty<string>();
    foreach (var str in strings)
    {
        var current = str.Split('\\', StringSplitOptions.RemoveEmptyEntries);
        int i;
        // Find where the first difference from the previous element is
        for (i = 0; i < Math.Min(current.Length, previous.Length); i++)
        {
            if (current[i] != previous[i])
            {
                break;
            }
        }
        // i now contains the index of the first difference
        // First, close off anything in previous which isn't in the current
        for (int j = i; j < previous.Length; j++)
        {
            writer.WriteEndElement();
        }
        // Then, any new elements
        for (int j = i; j < current.Length; j++)
        {
            writer.WriteStartElement("Item");
            writer.WriteAttributeString("value", current[j]);
        }

        previous = current;
    }

    writer.WriteEndDocument();
}

Дает:

<?xml version="1.0" encoding="utf-16"?>
<Items>
    <Item value="networkAdd">
        <Item value="users">
            <Item value="test1">
                <Item value="delete unicode character test">
                    <Item value="character test 1">
                        <Item value="linked to folder" />
                    </Item>
                    <Item value="character test 2" />
                    <Item value="character test 3" />
                </Item>
            </Item>
        </Item>
    </Item>
    <Item value="http:">
        <Item value="sp2013">
            <Item value="newTestsite" />
            <Item value="newTestlib">
                <Item value="sampleFolder" />
            </Item>
        </Item>
    </Item>
</Items>

Требуется немного поработать над обработкой :// et c, но принцип basi c должен будь здоров.

...