2010-06-09 5 views
3

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

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> 

ответ

0

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

/// <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; 
} 
1

Если 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

Вот что я думал, но несколько раз дерево глубже, а иногда это может быть «отрезаны» при различных длинах, и я бы просто предположить не написать случай для каждой возможности. – Andy

+0

@Andy: Вы можете добавить запрос xpath, чтобы сразу получить все ваши объекты logRotator ... затем проверьте, есть ли у них дети daysToKeep и numToKeep ... если нет ... добавьте их. Если это так ... перейдите на следующий logRotator. – Scott

+0

@Scott: Его (и наш) код использует метод '.Element()', который получает первый элемент, поэтому мы можем смело предположить, что это всего лишь один элемент. – Codesleuth

2

Это находит элемент 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()); 
+0

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

Смежные вопросы