Add node and elements in xml using C#/Linq - c#

I have an xml file like this,
<?xml version="1.0" encoding="utf-8" ?>
<root>
<FeaturedProductCategories>
<FeaturedProductCategory>
<FeaturedProducts>
<FeaturedProduct>
<ContentSelector datavalue_idtype="content:smartform" datavalue_displayvalue="«Smart Form:49»">49</ContentSelector>
</FeaturedProduct>
</FeaturedProducts>
</FeaturedProductCategory>
</FeaturedProductCategories>
</root>
I want to modify it like the one below,
<?xml version="1.0" encoding="utf-8" ?>
<root>
<Title>HomePage</Title>
<FeaturedProductCategories>
<FeaturedProductCategory>
<FeaturedProducts>
<FeaturedProduct>
<Products>
<Product>
<ProductTitle>Product</ProductTitle>
<ProductDate>03-08-2012 11:57:25</ProductDate>
<ProductImage>
<img src="ex1.jpg" />
</ProductImage>
<ProductThumbnailImage>
<img src="ex2.jpg" />
</ProductThumbnailImage>
<ProductCaption>Product Caption</ProductCaption>
<ProductImage>
<img src="ex3.jpg" />
</ProductImage>
<ProductThumbnailImage>
<img src="ex4.jpg" />
</ProductThumbnailImage>
<ProductCaption>Product Caption</ProductCaption>
</Product>
</Products>
</FeaturedProduct>
</FeaturedProducts>
</FeaturedProductCategory>
</FeaturedProductCategories>
</root>
All the new nodes and values are to be added through a C# function. Let us assume these new values as static values for now.
Also the node "FeaturedProduct" is not only one. There are a lot of nodes in that name. I want to modify all the "FeaturedProduct" nodes.

You should take a look at the XDocument class here:
http://msdn.microsoft.com/en-us/library/system.xml.linq.xdocument.aspx
I had to do something very similar to this a couple of weeks ago; XDocument is more willing to manipulate data, and using LINQ with it is incredibly easy.

This doesn't use linq exactly, but It will serve your purpose
XmlDocument xDoc = new XmlDocument();
xDoc.Load("filename.xml");
foreach (XmlNode xNode in xDoc.SelectNodes("//FeaturedProduct"))
{
XmlElement newElement = xDoc.CreateElement("newElementName");
XmlAttribute newAttribute = xDoc.CreateAttribute("AttributeName");
newAttribute.Value = "attributeValue";
newElement.Attributes.Append(newAttribute);
xNode.AppendChild(newElement);
xNode.InnerText = "myInnerText";
}
Also, This Documentation is a very handy reference for Xpath

Here's how to do it with Linq:
string documentXml = #"<?xml version=""1.0"" encoding=""utf-8"" ?>
<root>
<FeaturedProductCategories>
<FeaturedProductCategory>
<FeaturedProducts>
<FeaturedProduct>
<ContentSelector datavalue_idtype=""content:smartform"" datavalue_displayvalue=""«Smart Form:49»"">49</ContentSelector>
</FeaturedProduct>
</FeaturedProducts>
</FeaturedProductCategory>
</FeaturedProductCategories>
</root>";
string productsXml = #"<Products>
<Product>
<ProductTitle>Product</ProductTitle>
<ProductDate>03-08-2012 11:57:25</ProductDate>
<ProductImage>
<img src=""ex1.jpg"" />
</ProductImage>
<ProductThumbnailImage>
<img src=""ex2.jpg"" />
</ProductThumbnailImage>
<ProductCaption>Product Caption</ProductCaption>
<ProductImage>
<img src=""ex3.jpg"" />
</ProductImage>
<ProductThumbnailImage>
<img src=""ex4.jpg"" />
</ProductThumbnailImage>
<ProductCaption>Product Caption</ProductCaption>
</Product>
</Products>";
XDocument document = XDocument.Parse(documentXml);
var targetNodes = from featuredProduct in document.Descendants("FeaturedProduct")
from contentSelector in featuredProduct.Elements("ContentSelector")
select contentSelector;
foreach (var targetNode in targetNodes)
{
targetNode.ReplaceWith(XElement.Parse(productsXml));
}
Console.WriteLine(document.ToString());

Related

How to show specific information on xml

I have a c# console application where I update, add and delete information from an xml which works so far. But when i show the xml in my console with WriteLine it shows like this:
<ArrayOfKunde xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Kunde id="1">
<firstName>Hasan 2</firstName>
<lastName>sad</lastName>
<adress>sdfd</adress>
<birthday>vcxbgf</birthday>
<bankDetails>bcgh</bankDetails>
</Kunde>
<Kunde id="2">
<firstName>ghf</firstName>
<lastName>nbv</lastName>
<adress>bjk</adress>
<birthday>hjvn</birthday>
<bankDetails>jhgj</bankDetails>
</Kunde>
<Kunde id="3">
<firstName>mbn,</firstName>
<lastName>hgj</lastName>
<adress>ghj</adress>
<birthday>ghjg</birthday>
<bankDetails>hghj</bankDetails>
</Kunde>
</ArrayOfKunde>
it is probably due to my code to print it:
string filepath = "customerdatabase2.xml";
var xDoc = XDocument.Load(filepath);
Console.WriteLine(xDoc);
I wanted to ask if there is any way for me to filter what is shown? For example I do not want to show:
<ArrayOfKunde xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
Use: XDocument.Descendants
So your code can be:
string filepath = "customerdatabase2.xml";
var xDoc = XDocument.Load(filepath);
foreach (var node in xDoc.Descendants().Skip(1))
Console.WriteLine(node);
But this is very much tied to your Xml structure. Note that I am skipping 1st descendant because that will be the Top level ArrayOfKunde node.

Change XML element value in c#

My C# code:
XDocument doc = XDocument.Load(filename);
IEnumerable<XElement> collection =
doc.Elements("BCIRequest").Elements("Card").Elements("SelectedPIN");
My XML document:
<?xml version="1.0" encoding="utf-8"?>
<BCIRequest Version="2.0"
xmlns="urn:xxxxxx:bci:request">
<Header>
<SenderCode>XX99</SenderCode>
<SenderID>9999</SenderID>
<SequenceNumber>123</SequenceNumber>
<CardGroupCount>2</CardGroupCount>
<CardCount>4</CardCount>
<BlockCount>2</BlockCount>
</Header>
<!--card groups (must precede cards and blocks)-->
<CardGroup RequestID="1">
<CustomerNumber>XX01234567</CustomerNumber>
<CardGroupName Emboss="true">GROUP ONE</CardGroupName>
</CardGroup>
<CardGroup RequestID="2"
RequestRef="87416CB7-DAEF-483A-BD08-1A885531D958">
<CustomerNumber>XX12345678</CustomerNumber>
<CardGroupName Emboss="false">GROUP TWO</CardGroupName>
</CardGroup>
<Card RequestID="3">
<CustomerNumber>XX01234567</CustomerNumber>
<DriverCard>
<Driver Emboss="true">MARGE SIMPSON</Driver>
</DriverCard>
<CardTypeID>10</CardTypeID>
<PurchaseCategoryID>11</PurchaseCategoryID>
<Reissue>false</Reissue>
<GeneratedPIN/>
<OdoPrompt>false</OdoPrompt>
<CRNPrompt>false</CRNPrompt>
</Card>
<Card RequestID="4">
<CustomerNumber>XX12345678</CustomerNumber>
<VehicleCard>
<VRN Emboss="true">KYI 830</VRN>
</VehicleCard>
<CardTypeID>10</CardTypeID>
<PurchaseCategoryID>11</PurchaseCategoryID>
<Reissue>false</Reissue>
<SelectedPIN>0123</SelectedPIN>
<OdoPrompt>false</OdoPrompt>
<CRNPrompt>false</CRNPrompt>
</Card>
<Card RequestID="5">
<CustomerNumber>XX01234567</CustomerNumber>
<BearerCard>
<Bearer Emboss="true">OPEN XXXXXX</Bearer>
</BearerCard>
<CardTypeID>10</CardTypeID>
<PurchaseCategoryID>11</PurchaseCategoryID>
<Reissue>false</Reissue>
<FleetPIN/>
<OdoPrompt>false</OdoPrompt>
<CRNPrompt>false</CRNPrompt>
</Card>
<Block RequestID="6">
<CustomerNumber>XX01234567</CustomerNumber>
<PAN>7002999999999999991</PAN>
</Block>
<Card RequestID="7"
RequestRef="956EA6C5-7D7E-4622-94D0-38CAD9FCC8DF">
<CustomerNumber>XX01234567</CustomerNumber>
<DriverCard>
<Driver Emboss="true">HOMER SIMPSON</Driver>
<VRN Emboss="true">795 DVI</VRN>
</DriverCard>
<EmbossText>SPRINGFIELD POWER</EmbossText>
<CardTypeID>10</CardTypeID>
<TokenTypeID>20</TokenTypeID>
<PurchaseCategoryID>30</PurchaseCategoryID>
<ExpiryDate>2018-12</ExpiryDate>
<Reissue>true</Reissue>
<SelectedPIN>0123</SelectedPIN>
<OdoPrompt>true</OdoPrompt>
<CRNPrompt>true</CRNPrompt>
<!--address with optional fields specified-->
<CardDeliveryAddress OneTimeUse="false">
<ContactName>M xxxx</ContactName>
<ContactTitle>Mr</ContactTitle>
<CompanyName>Sxxxx</CompanyName>
<Line1>Sector 22-F</Line1>
<Line2>Springfield Power Plant</Line2>
<Line3>xxx Road</Line3>
<City>xxxx</City>
<Zipcode>xxxx</Zipcode>
<CountryCode>xxx</CountryCode>
</CardDeliveryAddress>
<!--address with only required fields-->
<PINDeliveryAddress OneTimeUse="true">
<Line1>xxxx</Line1>
<City>xxx</City>
<Zipcode>xxxx</Zipcode>
<CountryCode>xxxx</CountryCode>
</PINDeliveryAddress>
<Limits>
<Value Transaction="unlimited" Daily="200" Weekly="unlimited" Monthly="400"/>
<Volume Transaction="100" Daily="unlimited" Weekly="unlimited" Monthly="unlimited"/>
<Transactions Daily="unlimited" Weekly="unlimited" Monthly="unlimited"/>
<Day Monday="true" Tuesday="true" Wednesday="true" Thursday="true" Friday="true" Saturday="false" Sunday="false"/>
<Time Start="unlimited" End="17:00:00"/>
</Limits>
<Products>
<FuelProductRestrictionID>40</FuelProductRestrictionID>
<NonFuelProductRestrictionID>51</NonFuelProductRestrictionID>
<NonFuelProductRestrictionID>52</NonFuelProductRestrictionID>
<NonFuelProductRestrictionID>53</NonFuelProductRestrictionID>
<NonFuelProductRestrictionID>54</NonFuelProductRestrictionID>
<NonFuelProductRestrictionID>55</NonFuelProductRestrictionID>
</Products>
</Card>
<Block RequestID="8"
RequestRef="69A3E44D-DC10-4BEE-9249-1FC3C651BA0E">
<CustomerNumber>xxxxx</CustomerNumber>
<PAN>xxxxxx</PAN>
</Block>
</BCIRequest>
I need to update the element value in the above values. The old value is:
<SelectedPIN>0123</SelectedPIN>
And the new value should be:
<SelectedPIN EncryptedPIN="TKDS" FormNumber="000793906306">****</SelectedPIN>
Can anyone can help me on this?
If I selected the BCIRequest element, it's returning a null value. I've tried many solutions but unable to get one working on this XML file.
There many ways an Xml can be be modified, I prefer XDocument
XDocument doc = XDocument.Parse(input);
foreach (var element in doc.Descendants("SelectedPIN")) // filter if you want single element, in example I modifed for all elements.
{
element.Add(new XAttribute("EncryptedPIN", "TKDS"));
element.Add(new XAttribute("FormNumber", "000793906306"));
element.Value = "xxxxx"; //new value
}
and finally you can save the document using
doc.Save();
Take a look at this Demo
The root node (BCIRequest) contains a namespace so you need to include that into your query. Something like this should work:
XNamespace ns = "urn:xxxxxx:bci:request";
IEnumerable<XElement> collection = doc.Elements(ns + "BCIRequest").Elements(ns + "Card").Elements(ns + "SelectedPIN");

XMl Search and filter in windows phone

<?xml version="1.0" encoding="UTF-8"?>
<root>
<player>
<playerId>1234</playerId>
<playerName>ABCD</playerName>
<line>
<studentId>5612</studentId>
<studentName>WXYZ</studentName>
</line>
</player>
</root>
above shown is my XML,
I have to show "studentName" from XML with filter "playername"
so, how should I do it?
Thanks!
You can use LINQ2XML. Try this:
string xml = #"<?xml version='1.0' encoding='UTF-8'?>
<root>
<player>
<playerId>1234</playerId>
<playerName>ABCD</playerName>
<line>
<studentId>5612</studentId>
<studentName>WXYZ</studentName>
</line>
</player>
</root>";
var doc = XDocument.Parse(xml);
string studentName = (string)doc.Descendants("player")
.Where(p => (string)p.Element("playerName") == "ABCD")
.Descendants("studentName").First();
Looks like a chance for some LINQ to XML
See refs here and here for examples.

Merging XML Elements with LINQ

I have two XML documents.
My objective is to replace one of the nodes in the first document with the entire contents of the second Xml documents.
So the first document - Parent looks something like this:
<Root>
<AgencyName = "Some Agency"/>
<Originator = "Some other Agency"/>
<Type = "AnonymousType"/>
<Details/>
</Root>
The second document - children looks like this:
<Root>
<Details>
<Detail1>
...
</Detail1>
<Detail2>
...
</Detail2>
<Detail3>
...
</Detail3>
</Details>
</Root>
The node <Details/> has to be replaced with the contents of the second document.
I am attempting to use Linq to XML to do this. The first document is represented in an XDocument class and the second one is represented in an XElement class. There are several child attributes for <Detail/> and I haven't listed them here.
I am attempting to replace the element from the first document with this XElement class.
If I try something like this,
ParentDoc.Element("Details").ReplaceAll(children);
it is unlikely to work. How should I do the replace?
var doc = XDocument.Load(#"C:\Tools\test.xml");
var doc2 = XDocument.Load(#"C:\Tools\test2.xml");
var children = doc2.Root.Element("Details");
var parentNode = doc.Root.Element("Details");
parentNode.ReplaceWith(children);
By the way, your xml are not correct, so you'll get exceptions.
I tried with
<Root>
<AgencyName name= "Some Agency"/>
<Originator name= "Some other Agency"/>
<Type name= "AnonymousType"/>
<Details/>
</Root>
and
<Root>
<Details>
<Detail1>
asdf
</Detail1>
<Detail2>
asde
</Detail2>
<Detail3>
eere
</Detail3>
</Details>
</Root>
and got
<?xml version="1.0" encoding="utf-8"?>
<Root>
<AgencyName name="Some Agency" />
<Originator name="Some other Agency" />
<Type name="AnonymousType" />
<Details>
<Detail1>
asdf
</Detail1>
<Detail2>
asde
</Detail2>
<Detail3>
eere
</Detail3>
</Details>
</Root>

add nodes with attributes changes

I have the following xml:
<?xml version="1.0" encoding="utf-8" ?>
<AAA>
<BBB CCC="it is aatr 1" DDD="it is attr 2">
</AAA>
I want in my c# application to add several BBB nodes than my xml will look like this:
<?xml version="1.0" encoding="utf-8" ?>
<AAA>
<BBB CCC="it is aatr 1" DDD="it is attr 2">
<BBB CCC="it is another attr 1" DDD="it is another attr 2">
<BBB CCC="this is something else 1" DDD="this is something else 1">
</AAA>
any suggestion of code?
You may use DOM (System.Xml) and Linq to XML api.
Linq to XML
XDocument doc = XDocument.Load(file);
XElement ele = new XElement("BBB");
ele.SetAttributeValue("CCC", "text1");
ele.SetAttributeValue("DDD", "text2");
doc.Root.Add(ele);
doc.Save(file);

Categories