2010-06-09 4 views
3

J'écris un programme en C# qui va passer par un tas de fichiers config.xml et mettre à jour certains éléments, ou les ajouter s'ils n'existent pas. J'ai la partie vers le bas qui met à jour un élément si elle existe avec ce code:Dupliquer des éléments lors de l'ajout de XElement à XDocument

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

Mais je suis en cours d'exécution sur des questions quand je veux ajouter un élément qui n'existe pas. La plupart du temps, une partie de l'arbre est en place et quand j'utilise mon code, il ajoute un autre arbre identique, ce qui fait exploser le programme qui lit le xml.

voici comment je tente de le faire

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

et que les résultats dans une structure comme celui-ci (La balise numToKeep était déjà là):

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

mais ce que je veux

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

Répondre

0

Avec Kickstart de tout le monde ici, je fini par faire ceci et cela fonctionne. Il est loin d'être élégant, mais il fait le travail

/// <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

Si numToKeep existe déjà, essayez ceci:

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

Sinon, pour ajouter toute la ligne quand logRotator n'existe pas, utilisez:

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

Voir XElement.Add(Object[])

+0

C'est ce que je pensais, mais quelques fois l'arbre est plus profond et il peut parfois être « coupé » à différentes longueurs et je voudrais juste présumez pas écrire un cas pour chaque possibilité. – Andy

+0

@Andy: Pouvez-vous ajouter une requête xpath pour obtenir tous vos objets logRotator en même temps ... puis vérifiez s'ils ont les enfants daysToKeep et numToKeep ... sinon ... ajoutez-les. Si oui ... passez au logRotator suivant. – Scott

+0

@Scott: Son code (et notre) utilise la méthode '.Element()' qui obtient le premier élément, donc nous pouvons supposer qu'il ne s'agit que d'un seul élément. – Codesleuth

2

Ceci trouve l'élément logRotator pour un projet donné si elle existe et crée l'élément si ce n'est pas le cas. Pour la réutilisabilité (si vous avez d'autres éléments qui pourraient ou ne pourraient pas exister), vous pouvez extraire cela dans une méthode.

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)); 
} 

Test simple

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

Cela fonctionne pour ceux qui ne sont pas plus profonds que deux niveaux dans l'arbre. Je suis un peu flou sur ce qui se passe, mais j'essaie de voir si je peux adapter cela pour travailler avec des éléments qui sont profonds. Merci pour les aides jusqu'à présent – Andy

Questions connexes