如何将一个 XmlNodeList 拆分为两个子 XmlNodeList?
How do you split a XmlNodeList into two sub-XmlNodeList?
如何将一个 XmlNodeList 拆分为两个较小的 XmlNodeList,其中一个的大小为 N,另一个的总大小为 - N?
请参阅下面的示例以及我尝试使用它的地方:
public static void Main(string[] args)
{
XmlDocument someDoc = new XmlDocument();
someDoc.LoadXml(@"<bananas>
<banana tasty='yes'></banana>
<banana tasty='very'></banana>
<banana tasty='amazing'></banana>
<banana tasty='mind-blowing'></banana>
<banana tasty='disgusting'></banana>
</bananas>");
XmlNodeList bananaNodeList = someDoc.SelectNodes("//banana");
eatSomeBananas(bananaNodeList, 2);
}
/** Splits a XmlNodeList into two XmlNodeList, first one is a slice from 0 to numberOfBananas-1, and the other slice is from numberOfBananas and onwards
*/
public static void eatSomeBananas(XmlNodeList subBananaNodeList, int numberOfBananas)
{
XmlNodeList bananasToEat = subBananaNodeList.Cast<XmlNode>().Take(numberOfBananas) as XmlNodeList; //Error down-casting - null!
if (bananasToEat == null)
Console.WriteLine("Error! Did not work");
/*else
doSomethingHere(bananasToEat); */
XmlNodeList remainingBananas = subBananaNodeList.Cast<XmlNode>().Skip(numberOfBananas) as XmlNodeList; //Error down-casting - null!
eatSomeBananas(remainingBananas, numberOfBananas);
}
我试图将 XmlNodeList
转换为 IEnumerable<XmlNode>
(因为前者继承自后者)——我相信这应该是一个向上转换。之后我不应该将它转换回 XmlNodeList
吗?但如果不是,为什么不呢?
我刚刚转换为 IQueryable 并使用它,比 XmlNodeList 更容易使用。
public static void Main(string[] args)
{
XmlDocument someDoc = new XmlDocument();
someDoc.LoadXml(@"<bananas>
<banana tasty='yes'></banana>
<banana tasty='very'></banana>
<banana tasty='amazing'></banana>
<banana tasty='mind-blowing'></banana>
<banana tasty='disgusting'></banana>
</bananas>");
XmlNodeList bananaNodeList = someDoc.SelectNodes("//banana");
var allBananas = bananaNodeList.Cast<XmlNode>().AsQueryable();
eatSomeBananas(allBananas, 2);
}
public static void eatSomeBananas(IQueryable<XmlNode> subBananas, int numberOfBananas)
{
var bananasToEat = subBananas.Take(numberOfBananas);
var remainingBananas = subBananas.Skip(numberOfBananas);
Console.WriteLine(string.Format("Bananas to eat: {0}", bananasToEat.Count()));
Console.WriteLine(string.Format("Remaining bananas: {0}", remainingBananas.Count()));
if (!bananasToEat.Any())
Console.WriteLine("Error! Did not work (not enough bananas!)");
else
eatSomeBananas(remainingBananas, numberOfBananas);
}
输出:
Bananas to eat: 2
Remaining bananas: 3
Bananas to eat: 2
Remaining bananas: 1
Bananas to eat: 1
Remaining bananas: 0
Bananas to eat: 0
Remaining bananas: 0
Error! Did not work (not enough bananas!)
Shouldn't I be able downcast this back into a XmlNodeList afterwards? But if not, why not?
不,因为从 Skip
返回的值不是 XmlNodeList
。它仅被声明为 IEnumerable<XmlNode>
,我希望 Skip
实现可能使用迭代器块……如果 Skip
有任何详细的知识,我当然会感到惊讶XmlNodeList
。 Take
将以完全相同的方式工作。
就我个人而言,我会完全避免使用旧的 XML API,而只使用 LINQ to XML。这与 LINQ 一起自然发挥作用 - 通常更好 XML API,IMO。
你 没有 使用它,请注意 - 你可以将整个代码更改为使用 IEnumerable<XmlNode>
而不是 XmlNodeList
:
public static void eatSomeBananas(IEnumerable<XmlNode> subBananaNodeList, int numberOfBananas)
{
IEnumerable<XmlNode> bananasToEat = subBananaNodeList.Take(numberOfBananas);
IEnumerable<XmlNode> remainingBananas = subBananaNodeList.Skip(numberOfBananas);
// Added condition to avoid infinite recursion
if (remainingBananas.Any())
{
eatSomeBananas(remainingBananas, numberOfBananas);
}
}
那么调用方法的时候只调用Cast
一次即可:
eatSomeBananas(bananaNodeList.Cast<XmlNode>(), 2);
这里是 LINQ to XML 版本,我更喜欢它:
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
public class Test
{
public static void Main(string[] args)
{
XDocument someDoc = XDocument.Parse(
@"<bananas>
<banana tasty='yes'></banana>
<banana tasty='very'></banana>
<banana tasty='amazing'></banana>
<banana tasty='mind-blowing'></banana>
<banana tasty='disgusting'></banana>
</bananas>");
IEnumerable<XElement> bananas = someDoc.Descendants("banana");
EatSomeBananas(bananas, 2);
}
public static void EatSomeBananas(IEnumerable<XElement> bananas, int numberOfBananas)
{
var bananasToEat = bananas.Take(numberOfBananas);
Console.WriteLine("Eating some bananas");
foreach (var element in bananasToEat)
{
var tasty = element.Attribute("tasty").Value;
Console.WriteLine($"Tasty: {tasty}");
}
Console.WriteLine("Eaten the bananas");
var remainingBananas = bananas.Skip(numberOfBananas);
if (remainingBananas.Any())
{
EatSomeBananas(remainingBananas, numberOfBananas);
}
}
}
请注意,对于生产实施,我会避免递归并可能定期具体化结果 - 否则每次都会从头开始迭代,跳过加载然后进行一些加载。
如何将一个 XmlNodeList 拆分为两个较小的 XmlNodeList,其中一个的大小为 N,另一个的总大小为 - N?
请参阅下面的示例以及我尝试使用它的地方:
public static void Main(string[] args)
{
XmlDocument someDoc = new XmlDocument();
someDoc.LoadXml(@"<bananas>
<banana tasty='yes'></banana>
<banana tasty='very'></banana>
<banana tasty='amazing'></banana>
<banana tasty='mind-blowing'></banana>
<banana tasty='disgusting'></banana>
</bananas>");
XmlNodeList bananaNodeList = someDoc.SelectNodes("//banana");
eatSomeBananas(bananaNodeList, 2);
}
/** Splits a XmlNodeList into two XmlNodeList, first one is a slice from 0 to numberOfBananas-1, and the other slice is from numberOfBananas and onwards
*/
public static void eatSomeBananas(XmlNodeList subBananaNodeList, int numberOfBananas)
{
XmlNodeList bananasToEat = subBananaNodeList.Cast<XmlNode>().Take(numberOfBananas) as XmlNodeList; //Error down-casting - null!
if (bananasToEat == null)
Console.WriteLine("Error! Did not work");
/*else
doSomethingHere(bananasToEat); */
XmlNodeList remainingBananas = subBananaNodeList.Cast<XmlNode>().Skip(numberOfBananas) as XmlNodeList; //Error down-casting - null!
eatSomeBananas(remainingBananas, numberOfBananas);
}
我试图将 XmlNodeList
转换为 IEnumerable<XmlNode>
(因为前者继承自后者)——我相信这应该是一个向上转换。之后我不应该将它转换回 XmlNodeList
吗?但如果不是,为什么不呢?
我刚刚转换为 IQueryable 并使用它,比 XmlNodeList 更容易使用。
public static void Main(string[] args)
{
XmlDocument someDoc = new XmlDocument();
someDoc.LoadXml(@"<bananas>
<banana tasty='yes'></banana>
<banana tasty='very'></banana>
<banana tasty='amazing'></banana>
<banana tasty='mind-blowing'></banana>
<banana tasty='disgusting'></banana>
</bananas>");
XmlNodeList bananaNodeList = someDoc.SelectNodes("//banana");
var allBananas = bananaNodeList.Cast<XmlNode>().AsQueryable();
eatSomeBananas(allBananas, 2);
}
public static void eatSomeBananas(IQueryable<XmlNode> subBananas, int numberOfBananas)
{
var bananasToEat = subBananas.Take(numberOfBananas);
var remainingBananas = subBananas.Skip(numberOfBananas);
Console.WriteLine(string.Format("Bananas to eat: {0}", bananasToEat.Count()));
Console.WriteLine(string.Format("Remaining bananas: {0}", remainingBananas.Count()));
if (!bananasToEat.Any())
Console.WriteLine("Error! Did not work (not enough bananas!)");
else
eatSomeBananas(remainingBananas, numberOfBananas);
}
输出:
Bananas to eat: 2
Remaining bananas: 3
Bananas to eat: 2
Remaining bananas: 1
Bananas to eat: 1
Remaining bananas: 0
Bananas to eat: 0
Remaining bananas: 0
Error! Did not work (not enough bananas!)
Shouldn't I be able downcast this back into a XmlNodeList afterwards? But if not, why not?
不,因为从 Skip
返回的值不是 XmlNodeList
。它仅被声明为 IEnumerable<XmlNode>
,我希望 Skip
实现可能使用迭代器块……如果 Skip
有任何详细的知识,我当然会感到惊讶XmlNodeList
。 Take
将以完全相同的方式工作。
就我个人而言,我会完全避免使用旧的 XML API,而只使用 LINQ to XML。这与 LINQ 一起自然发挥作用 - 通常更好 XML API,IMO。
你 没有 使用它,请注意 - 你可以将整个代码更改为使用 IEnumerable<XmlNode>
而不是 XmlNodeList
:
public static void eatSomeBananas(IEnumerable<XmlNode> subBananaNodeList, int numberOfBananas)
{
IEnumerable<XmlNode> bananasToEat = subBananaNodeList.Take(numberOfBananas);
IEnumerable<XmlNode> remainingBananas = subBananaNodeList.Skip(numberOfBananas);
// Added condition to avoid infinite recursion
if (remainingBananas.Any())
{
eatSomeBananas(remainingBananas, numberOfBananas);
}
}
那么调用方法的时候只调用Cast
一次即可:
eatSomeBananas(bananaNodeList.Cast<XmlNode>(), 2);
这里是 LINQ to XML 版本,我更喜欢它:
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
public class Test
{
public static void Main(string[] args)
{
XDocument someDoc = XDocument.Parse(
@"<bananas>
<banana tasty='yes'></banana>
<banana tasty='very'></banana>
<banana tasty='amazing'></banana>
<banana tasty='mind-blowing'></banana>
<banana tasty='disgusting'></banana>
</bananas>");
IEnumerable<XElement> bananas = someDoc.Descendants("banana");
EatSomeBananas(bananas, 2);
}
public static void EatSomeBananas(IEnumerable<XElement> bananas, int numberOfBananas)
{
var bananasToEat = bananas.Take(numberOfBananas);
Console.WriteLine("Eating some bananas");
foreach (var element in bananasToEat)
{
var tasty = element.Attribute("tasty").Value;
Console.WriteLine($"Tasty: {tasty}");
}
Console.WriteLine("Eaten the bananas");
var remainingBananas = bananas.Skip(numberOfBananas);
if (remainingBananas.Any())
{
EatSomeBananas(remainingBananas, numberOfBananas);
}
}
}
请注意,对于生产实施,我会避免递归并可能定期具体化结果 - 否则每次都会从头开始迭代,跳过加载然后进行一些加载。