删除多个 XML 节点,如果其他一些节点不包含特定的子节点
Removing multiple XML Nodes, if some other nodes does not contains specific childs
我有一个复杂的 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>
的值必须在 <wForm>
元素的属性 number
中找到。所以 <vElement>
与 <wForm>
元素成对。
如果满足某些条件,我必须从此 xml 中删除一些 <vElement>
和 <wForm>
元素。条件如下:
- 如果元素
<vElement>
包含子元素 <elB>
,则此元素 不会 被删除。成对的<wForm>
元素也不会被删除。
- 如果元素
<vElement>
不包含子元素 <elB>
并且 <wForm>
不包含子元素 <kB>
它 将是 删除。
- 如果元素
<vElement>
不包含子元素 <elB>
但配对 <wForm>
包含子元素 <kB>
它将 NOT已删除。
- 一个
<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>
设置,并且 <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>
个子项并且不与无法删除的其他 <vElement>
成对。
如果可能,我想使用 Linq 从单行代码中删除 "removable" 个节点(<vElement>
和 <wForm>
)。我尝试了多个 foreach()
指令,但是很复杂,因为那些 "containing or not containing child elements" 东西 :(
谢谢。
这是我的解决方案。我更新了代码。 vElement 不包含 elb,因此您对 vElement 1 和 wForm 1 未被删除的评论是错误的。以下内容被删除:(1) vElement 3 & 4 (2) wForm 3。我正在使用 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; }
}
}
我不将此作为答案,因为它与我尝试发现的 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;
}
因此,据我了解,您的规则是删除满足以下条件的 <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;
}
我有一个复杂的 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>
的值必须在 <wForm>
元素的属性 number
中找到。所以 <vElement>
与 <wForm>
元素成对。
如果满足某些条件,我必须从此 xml 中删除一些 <vElement>
和 <wForm>
元素。条件如下:
- 如果元素
<vElement>
包含子元素<elB>
,则此元素 不会 被删除。成对的<wForm>
元素也不会被删除。 - 如果元素
<vElement>
不包含子元素<elB>
并且<wForm>
不包含子元素<kB>
它 将是 删除。 - 如果元素
<vElement>
不包含子元素<elB>
但配对<wForm>
包含子元素<kB>
它将 NOT已删除。 - 一个
<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>
设置,并且<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>
个子项并且不与无法删除的其他<vElement>
成对。
如果可能,我想使用 Linq 从单行代码中删除 "removable" 个节点(<vElement>
和 <wForm>
)。我尝试了多个 foreach()
指令,但是很复杂,因为那些 "containing or not containing child elements" 东西 :(
谢谢。
这是我的解决方案。我更新了代码。 vElement 不包含 elb,因此您对 vElement 1 和 wForm 1 未被删除的评论是错误的。以下内容被删除:(1) vElement 3 & 4 (2) wForm 3。我正在使用 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; }
}
}
我不将此作为答案,因为它与我尝试发现的 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;
}
因此,据我了解,您的规则是删除满足以下条件的 <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;
}