I want to use a regex to find the parent node of the 16 digit number and return that whole section, but can't figure out how, so given:
<Details>
<CreditCard cardnum="1234567890123456" ccv="123" exp="0212" cardType="1" name="joe" />
</Details>
I want to return:
<CreditCard cardnum="1234567890123456" ccv="123" exp="0212" cardType="1" name="joe" />
I then am going to use parse the xml and get every attribute that is a number and remove it.
I tried .*(\\d{13,16}).*
, but this gets every character.
Once, I do:
XElement element = XElement.Parse(xml); // XDocument.Load(xmlFile).Root
IEnumerable<XElement> elementsWithPossibleCCNumbers =
element.Descendants()
.Where(d => d.Attributes()
.Where(a => a.Value.Length == 16)
.Count() == 1);
I can't figure out how to loop through each attribute in elementsWithPossibleCCNumbers, for example:
foreach(var x in elementsWithPossibleCCNumbers)
{
//If attribute is number, replace value with empty string
}
Note: I removed the int.TryParse for now.
I decided to do this:
IEnumerable<XElement> elementsWithPossibleCCNumbers =
element.Descendants()
.Where(d => d.Attributes()
.Where(a => a.Value.Length >= 13 && a.Value.Length <= 16)
.Count() == 1).Select(x=>x);
foreach(var x in elementsWithPossibleCCNumbers)
{
foreach(var a in x.Attributes())
{
xml = xml.Replace(a.Value, new String('*',12));
}
}
However, if I have a second element with an attribute of 16 digits, it only replaces part of the attributes value.
I wrote up another method to try out. The regex now only verifies the attribute value and not the XML itself. I have no idea what you're looking to return out from this method but this will at least get you started on not using Regex for XML.
[Test]
public void X()
{
const string xml = "<Details><CreditCard cardnum=\"1234567890123456\" ccv=\"123\" exp=\"0212\" cardType=\"1\" name=\"joe\" /><donotfind>333</donotfind></Details>";
var doc = new XmlDocument();
doc.LoadXml(xml);
Console.WriteLine(doc.Name);;
foreach(XmlNode x in doc.ChildNodes)
{
ExploreNode(x);
}
}
void ExploreNode(XmlNode node)
{
Console.WriteLine(node.Name);
if (node.Attributes != null)
{
foreach (XmlAttribute attr in node.Attributes)
{
Console.WriteLine("\t{0} -> {1}", attr.Name, attr.Value);
if (attr.Value.Length == 16 && Regex.IsMatch(attr.Value, @"\d{16}"))
{
Console.WriteLine("\t\tCredit Card # found!");
}
}
}
foreach (XmlNode child in node.ChildNodes)
{
ExploreNode(child);
}
}
Since your XML can vary a great deal, I would do something like the following.
Assuming XML like:
<Details>
<CreditCard cardnum="1234567890123456"
ccv="123"
exp="0212"
cardType="1"
name="joe" />
</Details>
Agnostic-ish code:
XElement element = XElement.Parse(xml); // XDocument.Load(xmlFile).Root
int ccNumber;
IEnumerable<XElement> elementsWithPossibleCCNumbers =
element.Descendants()
.Where(d => d.Attributes()
.Where(a => a.Value.Length == 16)
.Where(a => int.TryParse(a.Value, out ccNumber))
.FirstOrDefault() != null);
// Do not use ccNumber
// Use elementsWithPossibleCCNumbers
This could be extended to include a number of attributes...
IEnumerable<XElement> elementsWithPossibleCCNumbers =
element.Descendants()
.Where(d => d.Attributes()
.Where(a => a.Value.Length == 16)
.Where(a => int.TryParse(a.Value, out ccNumber))
.FirstOrDefault() != null
&& d.Attributes().Count() == 5);
There are a multitude of possibilities that don't include using Regex nor hard coding XML element names. I tend to use Regex as a last resort, especially if there is something better that can parse all the data for me.
Update 1
elementsWithPossibleCCNumbers
are XML Elements that contain 1 or MORE attributes that are 16 digits in length and are an integer. That being the case, you can't tell so I would change it to..
IEnumerable<XElement> elementsWithPossibleCCNumbers =
element.Descendants()
.Where(d => d.Attributes()
.Where(a => a.Value.Length == 16)
.Where(a => int.TryParse(a.Value, out ccNumber))
.Count() == 1);
// Where only 1 attribute is 16 length and an int
Extending it again...
IEnumerable<XAttribute> attributesWithPossibleCCNumbers =
element.Descendants()
.Where(d => d.Attributes()
.Where(a => a.Value.Length == 16)
.Where(a => int.TryParse(a.Value, out ccNumber))
.Count() == 1)
.Select(e => e.Attributes()
.Where(a => a.Value.Length == 16)
.Where(a => int.TryParse(a.Value, out ccNumber))
.First());
Try using: <[^>]+[0-9]{16}[^>]+>
Edit: This might be more efficient- <([^>0-9]+)([0-9]{16})([^>]+)>
Don't use Regex to parse XML. It's not well suited to it.
How about using XmlDocument or XDocument instead?
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.