I am trying to delete/Scrub few elements from the xml using c# with the help of xpaths. I am trying to replace the value of social_security_number with "Scrubbed" in both the child tags named "Customers". But my program is landing in many errors. Please correct me.
xml :
<?xml version="1.0" encoding="utf-16"?>
<LoanApplications xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="12345" bundle_id="12225" version="1.0">
<LoanApplication payment_call="False" version="1.0" app_status="I" perform_dupe_check="1" bundle_id="12225" UpdateReviewed="True">
<Customers id = "12" name = "krish" ssn = "123456789">
</LoanApplication>
<LoanApplication deal_type="RESPONSE" payment_call="True" version="1.0" app_status="I" perform_dupe_check="1" bundle_id="12225" UpdateReviewed="True">
<Customers id = "12" name = "krish" ssn = "123456789">
</LoanApplication>
</LoanApplications>
Program :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
XmlDocument doc = new XmlDocument();
doc.Load("mytestfile.xml");
doc.SelectSingleNode("/LoanApplications/LoanApplication[#deal_type="%DealTypeALL%"]/LoanApplicationStates/LoanApplicationState/Customers/Customer[#customer_id="%CustIDALL%"]/").Attributes["social_security_number"].InnerText = "Scrubbed";
doc.Save("mytestfile.xml");
}
}
}
var doc = XDocument.Parse(System.IO.File.ReadAllText("C:\\Users\\jason\\Desktop\\Input\\2015\\09\\03\\mytestfile.xml"));
foreach (var customer in doc.Descendants("Customer"))
{
var ssn = customer.Attribute("social_security_number");
if (ssn != null)
{
ssn.Value = "scrubbed";
}
}
doc.Save("file.xml");
You have few needed nodes instead of one. Thus, you should use SelectNodes instead of SelectSingleNode method.
var doc = new XmlDocument();
doc.Load("mytestfile.xml");
var ssns = doc.SelectNodes("LoanApplications/LoanApplication/LoanApplicationStates/LoanApplicationState/Customers/Customer/#social_security_number");
foreach (XmlAttribute ssn in ssns)
ssn.InnerText = "Scrubbed";
doc.Save("mytestfile.xml");
You can use shorter XPath with descendants. But it has less performance.
var ssns = doc.SelectNodes("//Customer/#social_security_number");
This is real easy with xml linq
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
List<XElement> ss = doc.Descendants().Where(x => x.Attribute("social_security_number") != null).ToList();
foreach (XElement s in ss)
{
s.Attribute("social_security_number").Value = "Scrubbed";
}
}
}
}
Related
I have below XML.
<subscription>
<subscription_add_ons type="array">
<subscription_add_on>
<add_on_code>premium_support</add_on_code>
<name>Premium Support</name>
<quantity type="integer">1</quantity>
<unit_amount_in_cents type="integer">15000</unit_amount_in_cents>
<add_on_type>fixed</add_on_type>
<usage_percentage nil="true"></usage_percentage>
<measured_unit_id nil="true"></measured_unit_id>
</subscription_add_on>
</subscription_add_ons>
My XMLParse function
public XNode GetXmlNodes(XElement xml, string elementName)
{
List<string> addOnCodes= new List<string>();
//elementName = "subscription_add_ons ";
var addOns = xml.DescendantNodes().Where(x => x.Parent.Name == elementName).FirstOrDefault();
foreach (XNode addOn in addOns)
{
//Needed to do something like this
/*var len = "add_on_code".Length + 2;
var sIndex = addOn.ToString().IndexOf("<add_on_code>") + len;
var eIndex = addOn.ToString().IndexOf("</add_on_code>");
var addOnCode = addOn.ToString().Substring(sIndex, (eIndex - sIndex)).Trim().ToLower();
addOnCodes.Add(addOnCode);*/
}
As mentioned in comments by #JonSkeet, I updated my snippet as below.
var addOns = xml.Descendants(elementName).Single().Elements();
foreach (XNode addOn in addOns)
{
/*addon = {<subscription_add_on>
<add_on_code>premium_support</add_on_code>
<name>Premium Support</name>
<quantity type="integer">1</quantity>
<unit_amount_in_cents type="integer">15000</unit_amount_in_cents>
<add_on_type>fixed</add_on_type>
<usage_percentage nil="true"></usage_percentage>
<measured_unit_id nil="true"></measured_unit_id>
</subscription_add_on>} */
//how to get the addOnCode node value ?
var addOnCode = string.Empty;
addOnCodes.Add(addOnCode);
}
But what I need is from the passed XML, get all the nodes of type subscription_add_on then get the value contained in add_on_code & add it to string collection.
Or in general get the value of node by passing type ? Tried with the available methods coming from VS Intellisense but not getting the exact method that can do this?
Thanks!
Here is solution with Xml Linq (XDOCUMENT) :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication107
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
var results = doc.Descendants("subscription_add_on").Select(x => new
{
add_on_code = (string)x.Element("add_on_code"),
name = (string)x.Element("name"),
quantity = (int)x.Element("quantity"),
amount = (int)x.Element("unit_amount_in_cents"),
add_on_type = (string)x.Element("add_on_type")
}).ToList();
}
}
}
I have an xml file shown below which is small part of big xml file
<?xml version="1.0" encoding="utf-8" ?>
<xn:VsDataContainer id=test">
<xn:attributes>
<xn:vsDataType>vsDataEUtranCellFDD</xn:vsDataType>
<es:crsGain>0</es:crsGain>
<es:pciConflictCell>
<es:enbId>66111</es:enbId>
<es:cellId>3</es:cellId>
</es:pciConflictCell>
<es:pdcchLaGinrMargin>100</es:pdcchLaGinrMargin>
<es:lbEUtranAcceptOffloadThreshold>50</es:lbEUtranAcceptOffloadThreshold>
<es:pdcchCfiMode>5</es:pdcchCfiMode>
<es:cellId>0</es:cellId>
<es:zzzTemporary21>-2000000000</es:zzzTemporary21>
</xn:attributes>
</xn:VsDataContainer>
I am using following code to get values of crsGain and cellId.But cellIdiam not getting the desired one.. ie i need cellId if the previous node is pdcchCfiMode .so here i should get value as 0 ,but i am getting 3 which is the first in the sequence .How to solve this issue.Snippet Code i am using is
if (vsDataEUtranCellFDD.Any()) {
List<CellName> cells = vsDataEUtranCellFDD.Select(x => new CellName() {
cellId= (int)x.Descendants().Where(a => a.Name.LocalName == "cellId").FirstOrDefault(),
crsGain = (int)x.Descendants().Where(a => a.Name.LocalName == "crsGain").FirstOrDefault(),
EDIT
this cellid can happen in middle also ,only differentiation is previous node which is pdcchCfiMode
You can skip the elements while they are not equal to pdcchCfiMode then take the first element. Something like this:
cellId = (int)x.Descendants().SkipWhile(a => a.Name.LocalName != "pdcchCfiMode")
.Skip(1).Take(1).FirstOrDefault(),
Try code below
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
List<XElement> attributes = doc.Descendants().Where(x => x.Name.LocalName == "attributes").ToList();
XNamespace esNs = attributes.FirstOrDefault().GetNamespaceOfPrefix("es");
List<CellName> cells = attributes.Select(x => new CellName() {
cellId = (int)x.Element(esNs + "cellId"),
crsGain = (int)x.Element(esNs + "crsGain")
}).ToList();
}
}
public class CellName
{
public int cellId { get; set; }
public int crsGain { get; set; }
}
}
<?xml version="1.0" encoding="UTF-8"?>
<message xmlns="jabber:client" to="dev_345#localhost/unityXMPP" type="chat" xml:lang="en" from="dev_272#localhost/unityXMPP">
<archived xmlns="urn:xmpp:mam:tmp" id="1503375414608430" by="dev_345#localhost" />
<stanza-id xmlns="urn:xmpp:sid:0" id="1503375414608430" by="dev_345#localhost" />
<body>hi</body>
</message>
I wanted to parse the inner XML to fetch the id attribute.
I have created namespace whatsoever I have found. I am able to get to, from attributes. Below is the code in c#.
string value = "<message xmlns=\"jabber:client\" to=\"dev_345#localhost/unityXMPP\" type=\"chat\" xml:lang=\"en\" from=\"dev_272#localhost/unityXMPP\"><archived xmlns=\"urn:xmpp:mam:tmp\" id=\"1503375414608430\" by=\"dev_345#localhost\" /><stanza-id xmlns=\"urn:xmpp:sid:0\" id=\"1503375414608430\" by=\"dev_345#localhost\" /><body>hi</body></message>";
XmlDocument xmlDoc = new XmlDocument ();
XmlNamespaceManager namespaces = new XmlNamespaceManager (xmlDoc.NameTable);
namespaces.AddNamespace ("ns", "jabber:client");
namespaces.AddNamespace ("ns1", "urn:xmpp:mam:tmp");
xmlDoc.LoadXml (value);
XmlNode messageNode = xmlDoc.SelectSingleNode ("/ns:message", namespaces);
string sender = messageNode.Attributes ["from"].Value;
string receiver = messageNode.Attributes ["to"].Value;
string message = messageNode.InnerText;
XmlNode timeStampNode = xmlDoc.SelectSingleNode ("/ns:message/ns1:archived");
string timestamp = timeStampNode.Attributes ["id"].Value;
Does this help? I used LINQ To Xml
string xmltext = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><message xmlns=\"jabber:client\" to=\"dev_345#localhost/unityXMPP\" type=\"chat\" xml:lang=\"en\" from=\"dev_272#localhost/unityXMPP\"> <archived xmlns=\"urn:xmpp:mam:tmp\" id=\"1503375414608430\" by=\"dev_345#localhost\" /> <stanza-id xmlns=\"urn:xmpp:sid:0\" id=\"1503375414608430\" by=\"dev_345#localhost\" /> <body>hi</body></message>";
var xdoc = XDocument.Parse(xmltext);
foreach (var item in xdoc.Root.Descendants())
{
if (item.Name.LocalName == "archived")
Console.WriteLine(item.Attribute("id").Value);
}
It's better to use the XPath, if you dont want to de-/serialize the xml into an object (Link).
Or you can use the serialization, it's a very easy way to use json or xml inside your solution (Link 1, Link 2).
Try following xml linq to get all the data
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
var message = doc.Descendants().Where(x => x.Name.LocalName == "message").Select(x => new {
to = (string)x.Attribute("to"),
type = (string)x.Attribute("type"),
lang = (string)x.Attributes().Where(y => y.Name.LocalName == "lang").FirstOrDefault(),
from = (string)x.Attribute("from"),
messages = x.Elements().Select(y => new {
name = y.Name.LocalName,
id = (string)y.Attribute("id"),
by = (string)y.Attribute("by"),
value = (string)y
}).ToList()
}).FirstOrDefault();
}
}
}
<ENVELOPE>
<BODY>
<IMPORTDATA>
<REQUESTDATA>
<TALLYMESSAGE xmlns:UDF="TallyUDF">
<VOUCHER REMOTEID="4b6b9384" VCHKEY="4b6b9384" VCHTYPE="Payment" ACTION="Create" OBJVIEW="Accounting Voucher View">
<DATE>20160102</DATE>
</VOUCHER>
</TALLYMESSAGE>
</REQUESTDATA>
</IMPORTDATA>
</BODY>
</ENVELOPE>
this is the xml file,Now I want to serialize date into .net as like 01/02/2016(dd/mm/yy or mm/dd/yy format)
I tried this two way
objCompanyVouchar.VOUCHER_DATE=XmlConvert.ToDateTime(node.SelectSingleNode("DATE").InnerText)
objCompanyVouchar.VOUCHER_DATE = Convert.ToDateTime(node.SelectSingleNode("DATE").InnerText);
But it show the exception "String was not recognized as a valid DateTime."
Do anyone knows how can I solve this?
Nothing need to do with XmlConvert or required for Convert class.
Let's say you know the format is "yyyyMMdd", then what you need to do is:
var date= DateTime.ParseExact(node.SelectSingleNode("DATE").InnerText,"yyyyMMdd", CultureInfo.InvariantCulture);
objCompanyVouchar.VOUCHER_DATE= date; //If VOUCHER_DATE is DateTime
//objCompanyVouchar.VOUCHER_DATE = date.ToString(); //If VOUCHER_DATE is String
| you can choose the format you want, read more at ToString()
using System;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Serialization;
namespace XMLTest1
{
public class Test
{
public String value1;
public String value2;
}
class listtest
{
static void Main(string[] args)
{
XmlDocument myXml = new XmlDocument();
XPathNavigator xNav = myXml.CreateNavigator();
Test myTest = new Test() { value1 = "Value 1", value2 = "Value 2" };
XmlSerializer x = new XmlSerializer(myTest.GetType());
using (var xs = xNav.AppendChild())
{
x.Serialize(xs, myTest);
}
Console.WriteLine(myXml.OuterXml);
Console.ReadKey();
}
} }
Try xml linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
var inportData = doc.Descendants("IMPORTDATA").Select(x => new {
reportName = (string)x.Descendants("REPORTNAME").FirstOrDefault(),
company = (string)x.Descendants("SVCURRENTCOMPANY").FirstOrDefault(),
remoteID = (string)x.Descendants("VOUCHER").FirstOrDefault().Attribute("REMOTEID"),
vchKey = (string)x.Descendants("VOUCHER").FirstOrDefault().Attribute("VCHKEY"),
date = DateTime.ParseExact((string)x.Descendants("DATE").FirstOrDefault(), "yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture),
voucherName = (string)x.Descendants("VOUCHERTYPENAME").FirstOrDefault(),
voucherNumber = (int)x.Descendants("VOUCHERNUMBER").FirstOrDefault(),
ledgerName = (string)x.Descendants("PARTYLEDGERNAME").FirstOrDefault()
}).FirstOrDefault();
}
}
}
I'm using c# to get a parameters from xml file. My problem is I want to read only for the current program parameters. (v1.0, v1.1, v1.2... )
<?xml version="1.0" encoding="utf-8" ?>
<ApplicationPool>
<Resource Version="V1.0">
<Input>2000</Input>
<Input>210</Input>
<Input>65000</Input>
</Resource>
<Resource Version="V1.1">
<Input>2500</Input>
<Input>400</Input>
<Input>130000</Input>
</Resource>
</ApplicationPool>
using (XmlReader reader = XmlReader.Create("testXml.xml"))
{
while (reader.Read())
{
if (reader.IsStartElement())
{
if (reader["Version"] == actualVersion)
{
//??
}
}
}
}
XDocument doc = XDocument.Load("testXml.xml")
var result = doc.Root.Descendants("Resource")
.Where(x => x.Attribute("Version")!= null
&& x.Attribute("Version").Value == actualVersion);
This will return you all Resource nodes in which the Attribute Version == actualVersion. After that you can do whatever you want with the node.
if (reader["Version"] == actualVersion)
{
while (reader.ReadToFollowing("Input"))
{
string value = reader.ReadElementContentAsString();
// or
int value = reader.ReadElementContentAsInt();
}
}
You can use the Xml Linq Approach like:
var xmlFile= XElement.Load(xmlString);
var actualVersion = "V1.1";
var requiredXmlData = xmlFile.Elements("Resource").Where(c=>c.Attribute("Version").Value==actualVersion );
using System.Xml;
...
string actualVersion="V1.1";
XmlDocument rssDoc = new XmlDocument();
rssDoc.Load("testXML.xml");
XmlNodeList _ngroups = rssDoc.GetElementsByTagName("Resource");
for(int i=0;i<=_ngroups.Count-1;i++)
{
if(_ngroups[i].Attributes[0].InnerText.ToString()==actualVersion)
{
for(int j=0;j<=_ngroups[i].ChildNodes.Count-1;j++)
Console.WriteLine(_ngroups[i].ChildNodes[j].InnerText);
}
}
...
Using combination of XmlReader and xml linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
while (!reader.EOF)
{
if (reader.Name != "Resource")
{
reader.ReadToFollowing("Resource");
}
if (!reader.EOF)
{
XElement resource = (XElement)XElement.ReadFrom(reader);
string version = (string)resource.Attribute("Version");
}
}
}
}
}