我有一个复杂的xml,看起来像这样:
<rootElement>
<vElement number="0">
<!-- Next node, elB, could or could not appear -->
<elB>SomeData</elB>
<block>
<wFormNum>0</wFormNum>
</block>
</vElement>
<vElement number="1">
<block>
<wFormNum>1</wFormNum>
</block>
</vElement>
<vElement number="2">
<!-- Next node, elB, could or could not appear -->
<elB>SomeData</elB>
<block>
<wFormNum>0</wFormNum>
</block>
</vElement>
<vElement number="3">
<block>
<wFormNum>2</wFormNum>
</block>
</vElement>
<vElement number="4">
<block>
<wFormNum>3</wFormNum>
</block>
</vElement>
.
.
.
<wForm number="0">
</wForm>
<wForm number="1">
<kB number="0"></kB>
<kB number="1"></kB>
<kB number="2"></kB>
<kB number="3"></kB>
</wForm>
<wForm number="2">
<kB number="0"></kB>
<kB number="1"></kB>
<kB number="2"></kB>
<kB number="3"></kB>
<kB number="4"></kB>
<kB number="5"></kB>
<kB number="6"></kB>
<kB number="7"></kB>
</wForm>
<wForm number="3">
</wForm>
</rootElement>
如您所见,元素<vElement>
包含一个子元素<block>
,它也有一个子元素<wFormNum>
。 <wFormNum>
的值必须在number
元素的属性<wForm>
中找到。因此,<vElement>
与<wForm>
元素配对。
如果满足某些条件,我必须从此xml中删除一些<vElement>
和<wForm>
元素。条件如下:
<vElement>
包含子元素<elB>
,则将不删除该子元素。同样,成对的<wForm>
元素也不会被删除。<vElement>
不包含子元素<elB>
,而<wForm>
的元素不包含子元素<kB>
,则会将其删除。 <vElement>
不包含子元素<elB>
,但成对的<wForm>
包含子元素<kB>
,则将不删除。<wForm>
元素可以与多个<vElement>
成对。为了更清楚地说明,我将从上面的xml代码示例中给您介绍,必须删除哪些元素:
<vElement number="0">
不能删除,因为它包含子元素<elB></elB>
。同样,元素<wForm number="0">
也不会被删除,因为它与此<vElement number="0">
设置的<wFormNum>0</wformNum>
配对。<vElement number="1">
,因为它不包含子元素<elB></elB>
,但与<wForm number="1">
配对,由<wFormNum>1</wformNum>
设置,而{{1} }包含类型<wForm number="1">
的元素。因此,<kB>
和<vElement number="1">
将不会被删除。<wForm number="1">
与<vElement number="2">
相同,因此不会被删除。<vElement number="0">
与<vElement number="3">
相同,因此不会被删除,并且<vElement number="1">
也不会被删除。<wForm number="2">
将被删除,因为它不包含任何<vElement number="4">
子元素,并且<elB></elB>
不包含<wForm number="3">
子元素。 <kB></kB>
也将被删除,因为它不包含<wForm number="3">
个孩子,并且与其他无法删除的<kB>
不成对。如果可能的话,我想使用Linq从一行代码中删除“可移动”节点(<vElement>
和<vElement>
)。我尝试使用多个<wForm>
指令,但是很复杂,因为那些“包含或不包含子元素”的东西:(
谢谢。
答案 0 :(得分:0)
这是我的解决方案。我更新了代码。 vElement不包含elb,因此您对vElement 1和wForm 1没有被删除的评论是错误的。以下内容被删除:(1)vElement 3&4(2)wForm3。我正在使用xml linq。
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication9
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
List<WForm> wforms = doc.Descendants("wForm")
.Select(x => new WForm() { number = (int)x.Attribute("number"), element = x })
.ToList();
var results = (from vElement in doc.Descendants("vElement")
join wForm in wforms on (int)vElement.Attribute("number") equals wForm.number into v
from wForm in v.DefaultIfEmpty()
select new { vElement = vElement, wForm = wForm }
).ToList();
foreach (var result in results)
{
if (result.vElement.Element("elB") != null)
{
if (result.wForm != null) result.wForm.delete = false;
continue;
}
else
{
if (result.wForm != null)
{
if (result.wForm.element.Element("kB") != null)
{
result.wForm.delete = false;
}
continue;
}
else
{
int number = (int)result.vElement.Attribute("number");
Console.WriteLine("Remove vElement : '{0}'", number);
result.vElement.Remove();
}
}
}
foreach (WForm wForm in wforms)
{
if (wForm.delete)
{
Console.WriteLine("Remove wForm : '{0}'", wForm.number);
wForm.element.Remove();
}
}
Console.ReadLine();
}
}
public class WForm
{
public int number { get; set; }
public bool delete = true;
public XElement element { get; set; }
}
}
答案 1 :(得分:0)
我不投票作为答案,因为它与我尝试发现的LINQ版本有所不同,它具有简短且漂亮的可见代码,但这就是我要做的事情,工作和尊重的方面声明:
private static void RemoveEmptyWForms(string filePath, string vN, string rPN) {
XDocument xml = XDocument.Load(filePath);
List<wForm> listWForms = new List<wForm>();
List<Elements> listElements = new List<Elements>();
if (xml.Descendants("vElement").Count() == 0)
{
Console.WriteLine("File does not contains elements of type \"vElement\"!");
return;
}
else
{
foreach (XElement xe in xml.Descendants("vElement"))
{
Elements el = new Elements();
el.PNV = rPN + " | " + vN;
el.Node = xe;
el.Value = xe.Attribute("number").Value;
listElements.Add(el);
}
}
foreach (XElement xw in xml.Descendants("wForm"))
{
string value = xw.Attribute("number").Value;
wForm wfn = new wForm();
wfn.PNV = rPN + " | " + vN;
wfn.Node = xw;
wfn.Value = value;
if (xw.Descendants("kB").Count() > 0)
{
wfn.CanBeDeleted = false;
listWForms.Add(wfn);
continue;
}
wfn.CanBeDeleted = true;
listWForms.Add(wfn);
foreach (XElement xe in xml.Descendants("vElement")) {
if (xe.Descendants("elB").Count() > 0)
{
foreach (Elements el in listElements)
{
if (el.Node != xe) continue;
else {
el.CanBeDeleted = false;
break;
}
}
}
else {
string xeWfn = xe.Element("block").Element("wFormNum").Value;
foreach (wForm wf in listWForms) {
if (wf.Value.Equals(xeWfn))
{
if (wf.CanBeDeleted == false)
{
foreach (Elements el in listElements)
{
if (el.Node != xe) continue;
else
{
el.CanBeDeleted = false;
break;
}
}
break;
}
foreach (Elements el in listElements)
{
if (el.Node != xe) continue;
else
{
el.CanBeDeleted = true;
break;
}
}
}
}
}
}
}
foreach (wForm wf in listWForms) {
if (wf.CanBeDeleted) {
wf.Node.Remove();
Console.WriteLine("Removing wForm {0} from v {1}", wf.Value, wf.PNV);
}
}
foreach (Elements el in listElements) {
if (el.CanBeDeleted) {
el.Node.Remove();
Console.WriteLine("Removing element {0} from v {1}", el.Value, el.PNV);
}
}
}
class WaveForm {
public string PNV { get; set; }
public XNode Node { get; set; }
public string Value { get; set; }
public bool CanBeDeleted { get; set; } = true;
}
class Elements {
public string PNV{ get; set; }
public XNode Node { get; set; }
public string Value { get; set; }
public bool CanBeDeleted { get; set; } = true;
}
答案 2 :(得分:0)
因此,据我所知,您的规则是删除满足以下条件的<vElement>
节点:
<vElement>
不包含任何<elB>
个子节点。<vElement>
没有对应的<wForm>
元素,该元素不为空。XElement Cleanup(XElement element)
{
var clean = new XElement(element);
var nonEmptyForms = clean.XPathSelectElements("//wForm[*]")
.Select(f => (int)f.Attribute("number"))
.ToHashSet();
clean.XPathSelectElements("//vElement")
.Where(e => !e.Elements("elB").Any())
.Where(e => !nonEmptyForms.Contains((int)e.XPathSelectElement("block/wFormNum")))
.Remove();
return clean;
}