Parse XMPP inner xml - c#

<?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();
}
}
}

Related

How can I create a XML file containing the difference in value between another 2 XML files

Hello there C# enthusiast!
I am trying to create an XML file based on the elements subtraction of another two xml files ( the difference in value of elements)
For example:
The Source Xml files
Sought output:
Expected output
I did a quick research and found that there is a lib for XML content difference but none that fulfill this
functionality.
I know this can be solved by System.xml class , but I don't know exactly how to start.
Any help is appreciated.
XML Text Sample:
<?xml version="1.0" encoding="utf-8"?>
<Report>
<Project>
<Name>P1</Name>
<Runs>10</Runs>
<Errors>5</Errors>
<Successful>5</Successful>
</Project>
.
. Multiple Projects exists here
.
<Project>
<Name>P2</Name>
<Runs>12</Runs>
<Errors>3</Errors>
<Successful>9</Successful>
</Project>
<Timestamp>
<Year>2020</Year>
<Month>6</Month>
<Day>8</Day>
<Hour>12</Hour>
</Timestamp>
</Report>
Try xml linq. I assumed you had same Projects in both input and output files. If not you will need a left outer join. :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication3
{
class Program
{
const string INPUT_FILENAME_1 = #"c:\temp\test.xml";
const string INPUT_FILENAME_2 = #"c:\temp\test1.xml";
const string OUTPUT_FILENAME = #"c:\temp\test.xml2";
static void Main(string[] args)
{
XDocument doc1 = XDocument.Load(INPUT_FILENAME_1);
DateTime date1 = doc1.Descendants("Timestamp")
.Select(x => new DateTime(
(int)x.Element("Year"),
(int)x.Element("Month"),
(int)x.Element("Day"),
(int)x.Element("Hour"),
0, 0)).FirstOrDefault();
XDocument doc2 = XDocument.Load(INPUT_FILENAME_2);
DateTime date2 = doc2.Descendants("Timestamp")
.Select(x => new DateTime(
(int)x.Element("Year"),
(int)x.Element("Month"),
(int)x.Element("Day"),
(int)x.Element("Hour"),
0, 0)).FirstOrDefault();
string ident = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Report></Report>";
XDocument outputDoc = XDocument.Parse(ident);
XElement outputReport = outputDoc.Root;
XElement oldReport;
XElement newReport;
TimeSpan deltaTime;
if (date2 > date1)
{
newReport = doc2.Root;
oldReport = doc1.Root;
deltaTime = date2.Subtract(date1);
}
else
{
newReport = doc1.Root;
oldReport = doc2.Root;
deltaTime = date1.Subtract(date2);
}
var groups = (from n in newReport.Elements("Project")
join o in oldReport.Elements("Project")
on (string)n.Element("Name") equals (string)o.Element("Name")
select new { oldProj = o, newProj = n }
).ToList();
foreach (var group in groups)
{
XElement difference = new XElement("Project", new object[] {
new XElement("Name", (string)group.newProj.Element("Name")),
new XElement("Runs", (int)group.newProj.Element("Runs") - (int)group.oldProj.Element("Runs")),
new XElement("Errors", (int)group.newProj.Element("Errors") - (int)group.oldProj.Element("Errors")),
new XElement("Successful", (int)group.newProj.Element("Successful") - (int)group.oldProj.Element("Successful"))
});
outputReport.Add(difference);
}
XElement newTime = new XElement("Timestamp", new object[] {
new XElement("Year", 0),
new XElement("Month", 0),
new XElement("Day", deltaTime.Days),
new XElement("Hour", deltaTime.Hours)
});
outputReport.Add(newTime);
outputDoc.Save(OUTPUT_FILENAME);
}
}
}

How to get the node value by passing type in XDocument C#

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();
}
}
}

Append an existing child to the new child?

I have a xml file as:-
<Data>
<Caption>
</Caption>
</Data>
I added a new child CData in the the following code
foreach (XmlNode item in childNode.ChildNodes)
{
if (item.Name == "Data")
{
XmlCDataSection CData;
CData = xml2.CreateCDataSection("All Jane Austen novels 25% off starting 3/23!");
item.InsertBefore(CData, item.FirstChild);
foreach (XmlNode itemC in item.ChildNodes)
{
if (itemC.Name == "Caption")
{
XmlElement getTemplateID = xml2.CreateElement("TempalteID");
getTemplateID.InnerText = "10010";
itemC.AppendChild(getTemplateID);
//if (OptionsData[0].Key == "NoChilds")
//{
// XmlElement Getnochild = itemDoc.CreateElement("CaptionOptions");
// Getnochild.InnerText = "";
// itemC.AppendChild(Getnochild);
//}
//else
//{
XmlNode elemCap = xml2.CreateNode(XmlNodeType.Element, "CaptionOptions", null);
itemC.AppendChild(elemCap);
XmlElement Getelem1 = xml2.CreateElement("CaptionField");
elemCap.AppendChild(Getelem1);
XmlElement elem2 = xml2.CreateElement("FieldID");
XmlElement elem3 = xml2.CreateElement("FieldID");
elem2.InnerText = "#FieldId1";
elem3.InnerText = "#FieldId2";
XmlElement elem4 = xml2.CreateElement("TextString");
XmlElement elem5 = xml2.CreateElement("TextString");
elem4.InnerText = "#TextString1";
elem5.InnerText = "#TextString2";
Getelem1.AppendChild(elem2);
Getelem1.AppendChild(elem4);
Getelem1.AppendChild(elem3);
Getelem1.AppendChild(elem5);
//}
}
}
}
}
Now my final xml is coming as
<Data>
<![CDATA[All Jane Austen novels 25% off starting 3/23!]]>
<Caption>
<TempalteID>10010</TempalteID>
<CaptionOptions><CaptionField>
<FieldID>#FieldId1</FieldID>
<TextString>#TextString1</TextString>
<FieldID>#FieldId2</FieldID>
<TextString>#TextString2</TextString>
</CaptionField></CaptionOptions>
</Caption>
</Data>
But I want to make it as the following way....
<Data><![CDATA[<Caption xmlns="http://www.iin.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.happy.xsd">
<TemplateID>T000114-NOW</TemplateID>
<CaptionOptions>
<CaptionField>
<FieldID>NOW1</FieldID>
<TextString>"Ep 01"</TextString>
</CaptionField>
<CaptionField>
<FieldID>NOW2</FieldID>
<TextString>""</TextString>
</CaptionField>
</CaptionOptions>
</Caption>]]>
</Data>
So as you can see I basically wanted my newly added child CData to make <Caption> as it's child. So basically I want to create a child and make an existing child as it's child.(But I don't think I would still get the same format?")
How to do it?
Using xml Linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Runtime.InteropServices;
namespace ConsoleApplication23
{
class Program
{
static void Main(string[] args)
{
string xml = "<Data><Caption xmlns=\"http://www.iin.xsd\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.happy.xsd\"/></Data>";
XDocument doc = XDocument.Parse(xml);
XElement caption = doc.Descendants("Data").FirstOrDefault();
caption.Add(new XElement("TemplateID","T000114-NOW"));
XElement options = new XElement("CaptionOptions");
caption.Add(options);
foreach (Field field in Field.fields)
{
XElement newField = new XElement("CaptionField", new object[] { new XElement("FieldID", field.ID), new XElement("TextString", field.text)});
options.Add(newField);
}
}
}
public class Field
{
public static List<Field> fields = new List<Field>() {
new Field() { ID = "NOW1", text = "Ep 01"},
new Field() { ID = "Ep 01", text = ""}
};
public string ID { get; set; }
public string text { get; set; }
}
}
If I understand right, what you want to do is storing XML data in CDATA element. I want to remind you, that this is not what CDATA was intended to be used for, but here is example how to do that:
XmlDocument doc = new XmlDocument();
doc.LoadXml("<book genre='novel' ISBN='1-861001-57-5'>" +
"<title>Pride And Prejudice</title>" +
"</book>");
//Add the new node to the document.
XmlElement root = doc.DocumentElement;
XmlCDataSection CData;
CData = doc.CreateCDataSection(root.InnerXml);
root.RemoveAll();
root.AppendChild(CData);
doc.Save(Console.Out);

xml, xmlreader read only specific part using c#

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");
}
}
}
}
}

Scrub data from xml using c# and xpath

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";
}
}
}
}

Categories