我如何改进这个 linq to xml?
下面是 LINQ to XML 的问题:
有没有办法返回属性的枚举,这样我就不必执行 foreach 循环?
它应该只返回卡数在 13 到 16 位之间的元素,但它似乎返回比这更长的数字?为什么?
long.TryParse 是测试 16 位数字是否实际上是数字的最佳方法吗?
此外,是否可以不仅返回具有 16 位数字属性的元素,还可以返回具有内部文本的元素,例如
<前><代码> <详细信息>
,然后解析每个子元素1234567890123456
的父节点的节点,例如,xml 如下所示:283838383838383838 399 0202 <名字>乔
Here是代码:
long numeric;
string xml = @"<Details>
<CreditCard cardnum='1234888888823456'
ccv='123'
exp='0212'
cardType='1'
name='joe' />
<CreditCard cardnum='123488888882345633333'
ccv='123'
exp='0212'
cardType='1'
name='joe' />
</Details>";
XElement element = XElement.Parse(xml);
IEnumerable<XElement> elementsWithPossibleCCNumbers =
element.Descendants()
.Where(d => d.Attributes()
.Where(a => a.Value.Length >= 13 && a.Value.Length <= 16)
.Where(a => long.TryParse(a.Value, out numeric))
.Count() == 1).Select(x=>x);
foreach(var x in elementsWithPossibleCCNumbers)
{
foreach(var a in x.Attributes())
{
//Check if the value is a number
if(long.TryParse(a.Value,out numeric))
{
//Check if value is the credit card
if(a.Value.Length >= 13 && a.Value.Length <= 16)
xml = xml.Replace(a.Value, string.Concat(new String('*',a.Value.Length - 4),a.Value.Substring(a.Value.Length - 4)));
else //If value is not a credit card, replace it with ***
xml = xml.Replace(a.Value, "***");
}
}
}
好的,我明白为什么我认为它返回的数字超过 16,这是因为,前 16 位数字与第一个数字相同,我只是替换该部分,所以我我猜这会带来如何更新正确属性的问题。
更新总数的解决方案是使用正则表达式边界吗?
Here are the problems with the LINQ to XML below:
Is there a way to return an enumeration of the attributes so I don't have to do the foreach loop?
It should only return elements that have a cardnum between 13 and 16 digits, but it appears to be returning numbers longer than that? Why?
Is long.TryParse the best way to test if the 16 digit number is in fact a number?
Also, is it possible to return not only elements that have attributes with 16 digit numbers, but also elements with inner text such as
<ccnum>1234567890123456</ccnum>
and then parse every child node of the parent node of<ccnum>
, so for example, the xml would look like this:<details> <ccnum>283838383838383838</ccnum> <cvv>399</cvv> <exp>0202</exp> <name>joe</name> </details>
Here is the code:
long numeric;
string xml = @"<Details>
<CreditCard cardnum='1234888888823456'
ccv='123'
exp='0212'
cardType='1'
name='joe' />
<CreditCard cardnum='123488888882345633333'
ccv='123'
exp='0212'
cardType='1'
name='joe' />
</Details>";
XElement element = XElement.Parse(xml);
IEnumerable<XElement> elementsWithPossibleCCNumbers =
element.Descendants()
.Where(d => d.Attributes()
.Where(a => a.Value.Length >= 13 && a.Value.Length <= 16)
.Where(a => long.TryParse(a.Value, out numeric))
.Count() == 1).Select(x=>x);
foreach(var x in elementsWithPossibleCCNumbers)
{
foreach(var a in x.Attributes())
{
//Check if the value is a number
if(long.TryParse(a.Value,out numeric))
{
//Check if value is the credit card
if(a.Value.Length >= 13 && a.Value.Length <= 16)
xml = xml.Replace(a.Value, string.Concat(new String('*',a.Value.Length - 4),a.Value.Substring(a.Value.Length - 4)));
else //If value is not a credit card, replace it with ***
xml = xml.Replace(a.Value, "***");
}
}
}
OK, I got why it I thought it was returning the number longer than 16, it was because, the first 16 digits are the same as the first number and I am just replacing that part, so I guess that brings up the question of how to just update the correct attribute.
Is a solution to updating the whole number is to use a regex boundary?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
避免 foreach 循环:
并声明此方法:
它应该只返回卡数在 13 到 16 位之间的元素 [...] - 很高兴你已经解决了这个问题 :-)
I思考
long.TryParse
是检查所有字符是否都是数字的好方法。或者,您可以使用 @Henk Holterman 在他的答案中建议的正则表达式 - 这也摆脱了长度比较,使代码更短且更具可读性。对于具有内部文本的元素,您应该使用
element.Value
而不是foreach(a in element.Attributes)
->a.Value
To avoid the foreach loop:
and declare this method:
It should only return elements that have a cardnum between 13 and 16 digits [...] - glad you sorted that out :-)
I think
long.TryParse
is a good way to check if all characters are digits. Alternatively, you could use the regex that @Henk Holterman suggested in his answer - that also gets rid of the Length comparison, making the code shorter and more readable.In the case of elements with inner text, you should use
element.Value
instead offoreach(a in element.Attributes)
->a.Value
我会使用类似的东西:
或者,当
cardnum
可能丢失时:I would use something like:
or, when
cardnum
could be missing: