У меня есть XML файл, например
<Bars1>
<Bar name='0'>245</Bar>
<Bar name='1'>180</Bar>
<Bar name='2'>120</Bar>
<Bar name='3'>60</Bar>
<Bar name='4'>0</Bar>
</Bars1>
<Bars2>
<Bar name='0'>25</Bar>
<Bar name='1'>10</Bar>
<Bar name='2'>10</Bar>
<Bar name='3'>6</Bar>
<Bar name='4'>0</Bar>
</Bars2>
<Gubbins3>
<Bar name='0'>45</Bar>
<Bar name='1'>18</Bar>
<Bar name='2'>12</Bar>
<Bar name='3'>4</Bar>
<Bar name='4'>0</Bar>
</Gubbins3>
и List<int>
notNeededBarNames, содержащий, например, {1, 3}
Я загрузил XML файл в XmlDocument
xmlDoc и хочу удалить любой элемент "Bar", где атрибут "name" является одним из целых чисел из моего списка, независимо от того, где он может существовать в XML. Мой пример небольшой, но на самом деле документ и список могут быть довольно большими.
Есть ли хороший элегантный подход к этому? Я могу "переработать" его, но я не могу не чувствовать, что может быть лучший способ.
Надеюсь, ты поможешь!
Linq2Xml может облегчить жизнь.
var notNeededBarNames = new List<int>() { 1, 3 };
var xDoc = XDocument.Load(filename);
xDoc.Descendants("Bar")
.Where(bar => notNeededBarNames.Contains( (int)bar.Attribute("name")) )
.Remove();
var newXml = xDoc.ToString();
Для решения на основе xpath вы можете выбрать узлы для удаления следующим образом:
private static void TestXmlBars()
{
string s = @"<root>
<Bars1>...</Bars1>
<Bars2>...</Bars2>
<Gubbins3>...</Gubbins3>
</root>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(s);
List<int> exclude = new List<int>{1,2};
// create comma-delimited list
string list = "," + String.Join(",", exclude) + ",";
string xpath = String.Format("/root/*/Bar[contains('{0}', concat(',', @name, ','))]", list);
XmlNodeList nodesToExclude = doc.SelectNodes(xpath);
foreach (XmlNode node in nodesToExclude)
{
node.ParentNode.RemoveChild(node);
}
Console.WriteLine(doc.OuterXml);
}
(Обратите внимание, что xpath 1 ограничен, поскольку он не имеет функции "в", следовательно, "содержит" обходной путь - см. XPath 1.0, чтобы узнать, находится ли значение элемента в списке значений)
ToStringElements
?
Что-то вроде этого будет работать
using System;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
class Program
{
static void Main()
{
var notNeededBarNames = new[] {1, 3};
var elems = new[] {"Bars1", "Bars2", "Gubbins3"};
var newXDoc = new XElement("root");
var xDoc = XDocument.Load("PathToYourXmlFile");
foreach (var elem in elems)
{
newXDoc.Add(new XElement(elem));
var curElem = newXDoc.Elements(elem).Single();
string xpath = String.Format("root/{0}/Bar", elem);
var childElems = xDoc.XPathSelectElements(xpath);
foreach (var childElem in childElems)
{
bool add = true;
var nameAtt = childElem.Attribute("name");
if (nameAtt != null)
{
int val = Convert.ToInt32(nameAtt.Value);
if (notNeededBarNames.Any(x => x == val))
{
add = false;
}
}
if (add)
{
curElem.Add(childElem);
}
}
}
var newXml = newXDoc.ToString();
}
}
I can "brute force" it
сначала сделать, чем задать конкретную проблему о вашем коде.