Повторяющиеся элементы при добавлении XElement в XDocument - PullRequest
3 голосов
/ 09 июня 2010

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

XDocument xdoc = XDocument.Parse(ReadFile(_file));
XElement element = xdoc.Elements("project").Elements("logRotator")
                        .Elements("daysToKeep").Single();
element.Value = _DoRevert;

Но у меня возникают проблемы, когда я хочу добавить элемент, который не существует. Большую часть времени часть дерева находится на своем месте, и когда я использую свой код, он добавляет другое идентичное дерево, и это приводит к взрыву программы, читающей XML.

вот как я пытаюсь это сделать

xdoc.Element("project").Add(new XElement("logRotator", new XElement("daysToKeep", _day)));

и это приводит к такой структуре (тег numToKeep уже был там):

<project>
  <logRotator>
    <daysToKeep>10</daysToKeep>
  </logRotator>
  <logRotator>
    <numToKeep>13</numToKeep>
  </logRotator>
</project>

но это то, что я хочу

<project>
  <logRotator>
    <daysToKeep>10</daysToKeep>
    <numToKeep>13</numToKeep>
  </logRotator>
</project>

Ответы [ 3 ]

2 голосов
/ 09 июня 2010

Находит элемент logRotator для данного проекта, если он существует, и создает элемент, если его нет.

// project is XElement
XElement logRotator = project.Element("logRotator");

if (logRotator == null)
{
    logRotator = new XElement("logRotator");
    project.Add(logRotator);
}

logRotator.Add(new XElement("daysToKeep", someValue));

Для возможности повторного использования (если у вас есть другие элементы, которые могут или не могут существовать), вы можете извлечь это в метод.

static void AddToElement(XElement outerParent, string innerParent, string name, object value)
{
    XElement inner = outerParent.Element(innerParent);
    if (inner == null)
    {
        inner = new XElement(innerParent);
        outerParent.Add(inner);
    }

    inner.Add(new XElement(name, value));
}

Простой тест

string xml = @"<project> 
                    <logRotator> 
                    <numToKeep>13</numToKeep> 
                    </logRotator> 
                </project>";

XDocument document = XDocument.Parse(xml);
XElement project = document.Element("project");
AddToElement(project, "logRotator", "daysToKeep", 10);

Console.WriteLine(document.ToString());
1 голос
/ 09 июня 2010

Если numToKeep уже существует, попробуйте это:

xdoc.Element("project")
    .Element("logRotator")
    .Add(new XElement("daysToKeep", _day));

В противном случае, чтобы добавить всю строку, когда logRotator не существует, используйте:

xdoc.Element("project").Add(
    new XElement("logRotator", 
        new XElement("daysToKeep", _day),
        new XElement("numToKeep", _num)
));

См. XElement.Add(Object[])

0 голосов
/ 09 июня 2010

С кикстартом от всех здесь я закончил делать это, и это работает.Это далеко не элегантно, но оно выполняет свою работу

/// <summary>
/// adds an element to an xml tree and builds the tree up if it is needed
/// </summary>
/// <param name="outerParent">root node</param>
/// <param name="innerPath">root/childOne/innerParent/name</param>
/// <param name="name">element to add</param>
/// <param name="value">elements value</param>
static XElement BuildTree(XElement outerParent, string innerParentPath, string name, object value)
{
    List<string> s = innerParentPath.Split('/').ToList(); 
    string str = "";
    XElement prevInner = null;
    if (s.Count != 2)//use 2 since we know the root will always be there
    {
        var t = new List<string>(s);
        t.RemoveRange(s.Count - 1, 1);//remove last element
        string[] sa = t.ToArray();
        str = string.Join("/", sa);
        prevInner = BuildTree(outerParent, str, name, value);//call recursively till we get to root;
    }
    else
    {
        prevInner = outerParent;
    }
    XElement inner = prevInner.Element(s[s.Count - 1]);
    if (inner == null)
    {
        if (s[s.Count - 1] == name)//add actual element if we're at top lvl.
        {
            prevInner.Add(new XElement(name, value));
        }
        else
        {
            inner = new XElement(s[s.Count - 1]);
            prevInner.Add(inner);
        }
    }
    return inner;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...