2013-11-14 2 views
2

Вот мой Xmlмне нужен InsertBefore или InsertAfter в родительском не ребенок

<root> 
<categories> 
    <recipe id="RecipeID2"> 
     <name>something 1</name> 
    </recipe> 
    <recipe id="RecipeID2"> 
     <name>something 2</name> 
    </recipe> 
    <recipe id="RecipeID3"> 
     <name>something 3</name> 
    </recipe> 
</categories> 
</root> 

Я разбор всех рецепты, где клиент хочет вставить новый рецепт до или после

XmlDocument xmlDocument = new XmlDocument(); 

xmlDocument.Load("thexmlfiles.xml"); 

XmlNodeList nodes = xmlDocument.SelectNodes("/root/categories//Recipe"); 

foreach (XmlNode node in nodes) 
{ 
    if (node.Attributes["id"].InnerText == comboBoxInsertRecipe.Text) 
    { 
     node.InsertAfter(xfrag, node.ChildNodes[0]); 
    } 
} 

Ожидаемый результат:

<root> 
<categories> 
    <recipe id="RecipeID2"> 
     <name>something 1</name> 
    </recipe> 
    <recipe id="RecipeID2"> 
     <name>something 2</name> 
    </recipe> 
    <recipe id="NewRecipe4"> 
     <name>new Recipe 4</name> 
    </recipe> 
    <recipe id="RecipeID3"> 
     <name>something 3</name> 
    </recipe> 
</categories> 
</root> 

, но когда я вставляю мои новые рецепты его делает, как этот

<root> 
<categories> 
    <recipe id="RecipeID2"> 
     <name>something 1</name> 
    </recipe> 
    <recipe id="RecipeID2"> 
     <name>something 2</name> 
    </recipe> 
    <recipe id="RecipeID3"> 
     <name>something 3</name> 
     <recipe id="NewRecipe4"> 
      <name>new Recipe 4</name> 
     </recipe> 
    </recipe> 
</categories> 
</root> 

Новый рецепт внутри другого рецепта, но не внутри категорий

+1

Вы выбираете все узлы '' в списке 'nodes', поэтому, конечно, если вы добавите что-то к такому узлу, он будет внутри узла' '. Вам нужно сделать вкладку в ** родительский ** вашего узла рецепта - что-то вроде: 'node.parent.Insert (....);' –

ответ

2

первых, я рекомендую использовать LINQ-to-Xml. Образец L2Xml в этом ответе.

XDocument xmlDocument = XDocument.Load("thexmlfiles.xml"); 
var root = xmlDocument.Root; 
var recipes = root.Element("categories").Elements("recipe"); 

Во-вторых, получите ручку/ссылку на узел, который вы хотите вставить до/после.

var currentRecipe = recipes.Where(r => r.Attribute("id") == "RecipeID3") 
    .FirstOrDefault(); 

... затем добавьте в случае необходимости (с помощью XElement.AddAfterSelf или XElement.AddBeforeSelf):

void AddNewRecipe(XElement NewRecipe, bool IsAfter, XElement CurrentRecipe) { 
    if(IsAfter) { 
     CurrentRecipe.AddAfterSelf(NewRecipe); 
    } else { 
     CurrentRecipe.AddBeforeSelf(NewRecipe); 
    } 
} 
1

Вы добавляете новый узел на неправильном уровне документа. Элемент должен быть добавлен (как указано) к узлу категории, а не к узлу sibling. У вас есть два варианта, чтобы найти правильный узел, а затем добавить узел в правильное положение:

  • , как вы это делаете, перебирает все узлы в поисках матча
  • найти узел непосредственно с помощью XPath /путь/элемент [@ атрибут = 'ATTRIBUTENAME']

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

XmlDocument xmlDocument = new XmlDocument(); 
xmlDocument.Load(@"d:\temp\thexmlfile.xml"); 
XmlNodeList nodes = xmlDocument.SelectNodes("/root/categories/recipe"); 
// root node 
XmlNodeList category = xmlDocument.SelectNodes("/root/categories"); 
// test node for the example 
var newRecipe = xmlDocument.CreateNode(XmlNodeType.Element, "recipe", ""); 
var newInnerNode = xmlDocument.CreateNode(XmlNodeType.Element, "name", ""); 
newInnerNode.InnerText = "test"; 
var attribute = xmlDocument.CreateAttribute("id"); 
attribute.Value = "RecipeID4"; 
newRecipe.Attributes.Append(attribute); 
newRecipe.AppendChild(newInnerNode); 
// variant 1; find node while iteration over all nodes 
foreach (XmlNode node in nodes) 
{ 
    if (node.Attributes["id"].InnerText == "RecipeID3") 
    { 
     // insert into the root node after the found node 
     category[0].InsertAfter(newRecipe, node); 
    } 
} 
// variant 2; use XPath to select the element with the attribute directly 
//category[0].InsertAfter(newRecipe, xmlDocument.SelectSingleNode("/root/categories/recipe[@id='RecipeID3']")); 
// 
xmlDocument.Save(@"d:\temp\thexmlfileresult.xml"); 

Выход:

<root> 
    <categories> 
     <recipe id="RecipeID1"> 
      <name>something 1</name> 
     </recipe> 
     <recipe id="RecipeID2"> 
      <name>something 2</name> 
     </recipe> 
     <recipe id="RecipeID3"> 
      <name>something 3</name> 
     </recipe> 
     <recipe id="RecipeID4"> 
      <name>test</name> 
     </recipe> 
    </categories> 
</root> 

Как также предложил, чтобы Вы могли сделать это с LINQ2XML. Код может выглядеть так:

// load document ... 
var xml = XDocument.Load(@"d:\temp\thexmlfile.xml"); 
// find node and add new one after it 
xml.Root      // from root 
    .Elements("categories")  // find categories 
    .Elements("recipe")   // all recipe nodes 
    .FirstOrDefault(r => r.Attribute("id").Value == "RecipeID3") // find node by attribute 
    .AddAfterSelf(new XElement("recipe",       // create new recipe node 
        new XAttribute("id", "RecipeID4"),    // with attribute 
        new XElement("name", "test")));     // and content - name node 
// and save document ... 
xml.Save(@"d:\temp\thexmlfileresult.xml"); 

Выход такой же. LINQ2XML во многих отношениях проще и удобнее в использовании, чем XmlDocument. Например отбор подузлов может быть намного проще и вам не нужна строка XPath:

xml.Descendants("recipe"); 

LINQ2XML это стоит того, чтобы дать ему попробовать.