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>
Related
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.
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 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.
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());
If i have an XML file settings.xml like below
<Root>
<First>
</First>
</Root>
I Load the XML first using XDocument settings = XDocument.Load("settings.xml")
How should I insert a XML node inside the node First and save it using LINQ-to-XML?
First you need to find the First element. Then you can add other elements and attributes to it.
There are more than one way to find an element in the xml: Elements, Descendants, XPathSelectElement, etc.
var firstElement = settings.Descendants("First").Single();
firstElement.Add(new XElement("NewElement"));
settings.Save(fileName);
// or
var newXml = settings.ToString();
Output:
<Root>
<First>
<NewElement />
</First>
</Root>
Or element with attribute:
firstElement.Add(
new XElement("NewElement", new XAttribute("NewAttribute", "TestValue")));
Output:
<Root>
<First>
<NewElement NewAttribute="TestValue" />
</First>
</Root>
[Edit] The answer to the bonus question. What to do if the first element does not exist and I want to create it:
var root = settings.Element("Root");
var firstElement = root.Element("First");
if (firstElement == null)
{
firstElement = new XElement("First");
root.Add(firstElement);
}
firstElement.Add(new XElement("NewElement"));