I have the following XML File. I want to copy a new "Test" and change the ID of the Test. How is it possible?
I already can copy the nodes, unfortunately not on the correct position (see images) and I also can´t change the ID.
Anyone have a solution for me?
Before:
After:
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(Before.xml");
XmlNode Set = xmldoc.DocumentElement;
string strXmlQuery = "/Toolings/Testing/Test1";
XmlNode NodeToCopy = Set.SelectSingleNode(strXmlQuery);
XmlNode NewNode = NodeToCopy.CloneNode(true);
NodeToCopy.AppendChild(NewNode);
Set.InsertAfter(NewNode, Set.LastChild);
XPathNavigator navigator = xmldoc.CreateNavigator();
navigator.MoveToRoot();
navigator.MoveToFirstChild();
navigator.MoveToFirstChild();
navigator.MoveToFirstChild();
navigator.MoveToFirstChild();
navigator.SetValue("5678");
xmldoc.Save(After.xml");
Here is an example using System.Xml.Linq.XDocument which is a much easier API than XmlDocument:
//You can also use Load(), this is just so I didn't have to make a file
XDocument doc = XDocument.Parse("<Toolings><Testing><Test><ID>1234</ID></Test></Testing></Toolings>");
//Grab the first Test node (change the predicate if you have other search criteria)
var elTest = doc.Descendants().First(d => d.Name == "Test");
//Copy the node, only necessary if you don't know the structure at design time
XElement el = new XElement(elTest);
el.Element("ID").Value = "5678";
//inject new node
elTest.AddAfterSelf(el);
doc.Save("After.xml");
Related
I am new to C#, kindly help me. How to remove the single xml element node 'PaymentRecord' and content inside that should not get deleted.
<Payments>
<PaymentRecord>
<PayId>2031</PayId>
<Reference>Policy03</Reference>
<StatusCode>ACV</StatusCode>
<MethodDetail>
<PaymentMethodDetail>
<CardPaymentDetails>
<CardHolderName>abcded</CardHolderName>
<CardTransactionDetails>
<StoredCard>N</StoredCard>
</CardTransactionDetails>
</CardPaymentDetails>
</PaymentMethodDetail>
</MethodDetail>
<CurrencyCode>USD</CurrencyCode>
</PaymentRecord>
</Payments>
I need to remove "PaymentRecord" element from the XML. I need like below
<Payments>
<PayId>2031</PayId>
<Reference>Policy03</Reference>
<StatusCode>ACV</StatusCode>
<MethodDetail>
<PaymentMethodDetail>
<CardPaymentDetails>
<CardHolderName>abcded</CardHolderName>
<CardTransactionDetails>
<StoredCard>N</StoredCard>
</CardTransactionDetails>
</CardPaymentDetails>
</PaymentMethodDetail>
</MethodDetail>
<CurrencyCode>USD</CurrencyCode>
</Payments>
I have tried my below code, but its deleting the complete node which I don't want to do :- here 'queuePayload' is the xml element
XmlNodeList payloadRecordList = queuePayload.SelectNodes("//Payments/PaymentRecord");
foreach (XmlElement singleNode in payloadRecordList)
{
XmlHelper.removeElem((XmlElement)singleNode.ParentNode, "//PaymentRecord");
XmlDocument xmlDoc = singleNode.OuterXml;
// my remaining logic goes based on "xmldoc" value - I will inserting this data to table
}
You can use System.Xml.Linq with its XDocument to achiev this. Load the input and create a new document out of it like:
XDocument inputDoc = XDocument.Load(inputFile, LoadOptions.None);
XDocument outputDoc = new XDocument();
var elements = inputDoc.Element("Payments").Elements().Select(pr => pr.Elements());
XElement newElement = new XElement("Payments");
foreach (var element in elements)
{
newElement.Add(element);
}
outputDoc.Add(newElement);
Console.WriteLine(outputDoc.ToString());
I think #Fructzwerg is slightly overcomplicating it.
You can remove the PaymentRecord node and add all its children to the root in one go.
var xDoc = XDocument.Load(filePath);
var paymentRecord = xDoc.Root.Element("PaymentRecord");
var nodes = xDoc.Root.Element("PaymentRecord").Elements();
paymentRecord.Remove();
xDoc.Root.Add(nodes);
Console.WriteLine(xDoc.ToString());
dotnetfiddle
I have xml file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><SENT_110 xmlns:ns2="http://www.mf.gov.pl/SENT/2017/01/18/STypes.xsd" xmlns="http://www.mf.gov.pl/SENT/2017/01/18/SENT_110.xsd"><SentNumber>SENT20180416000032</SentNumber><KeyNumber><ns2:SenderKey>KS-28YM</ns2:SenderKey><ns2:RecipientKey>KR-52DH</ns2:RecipientKey><ns2:CarrierKey>KD-48WW</ns2:CarrierKey></KeyNumber>
I want to read in separate SenderKey, RecipientKey & CarrierKey.
When i use this code:
XmlTextReader reader = new XmlTextReader(file);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(reader);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
nsmgr.AddNamespace("ns", xmlDoc.DocumentElement.NamespaceURI);
XmlNodeList nodeList = xmlDoc.SelectNodes("/ns:SENT_110/ns:KeyNumber", nsmgr);
foreach (XmlNode node in nodeList)
{
key = node.InnerText;
MessageBox.Show(key);
}
i've got something like this: KS-28YMKR-52DHKD-48WW, without any separate between key.
How i could read only one key?
Use the following XPath:
"/ns:SENT_110/ns:KeyNumber/*"
It will return all nested nodes to you.
If the structure of the XML is fixed it is rather easy by using XDocument:
var xmlText = "<SENT_110 xmlns:ns2=\"http://www.mf.gov.pl/SENT/2017/01/18/STypes.xsd\" xmlns=\"http://www.mf.gov.pl/SENT/2017/01/18/SENT_110.xsd\"><SentNumber>SENT20180416000032</SentNumber><KeyNumber><ns2:SenderKey>KS-28YM</ns2:SenderKey><ns2:RecipientKey>KR-52DH</ns2:RecipientKey><ns2:CarrierKey>KD-48WW</ns2:CarrierKey></KeyNumber></SENT_110>";
var xml = XDocument.Parse(xmlText);
var nodes = xml.Descendants();
var senderKey = nodes.First(d => d.Name.ToString().EndsWith("SenderKey")).Value;
var recipientKey = nodes.First(d => d.Name.ToString().EndsWith("RecipientKey")).Value;
var carrierKey = nodes.First(d => d.Name.ToString().EndsWith("CarrierKey")).Value;
See HERE for a working snippet. If this is just a part of a bigger XML or the structure can be different maybe some more complex searching is needed.
I have a dtsConfig file with configuration for ssis package variable User::Quote_ID:
<Configuration ConfiguredType="Property"
Path="\Package.Variables[User::Quote_ID].Properties[Value]"
ValueType="String"><ConfiguredValue>77777</ConfiguredValue></Configuration>
I want to change this value from c# code:
XmlDocument xDoc = new XmlDocument();
xDoc.Load(#"\\MyServer\DataFiles$\...\MyConfigFile.dtsConfig");
XmlNode xFile = xDoc.SelectSingleNode("User::Quote_ID");
xFile.Value = quote_ID.ToString();
xDoc.Save(#"\\MyServer\DataFiles$\...\MyConfigFile.dtsConfig");
xDoc = null;
It gives me an error on the third line of my code (XmlNode...):
‘User::Quote_ID’ has an invalid token
What is wrong?
Chris! Your code helped me a lot! In my case it did not work thought. I ran the application in debug mode and I could see that xDoc.Load... opens the right file, but it did not execute foreach loop. The property listOfConfigurationNodes had Count = 0. I checked my xml file again and found that it has outer node and all nodes inside this outer node. So I changed your code
XmlNodeList listOfConfigurationNodes = xDoc.SelectNodes("Configuration");
I made:
XmlNode XMLOuterNode = xDoc.SelectSingleNode("DTSConfiguration");
XmlNodeList listOfConfigurationNodes = XMLOuterNode.SelectNodes("Configuration");
This code works fine for my particular case. Thanks a lot!!!
The node name is "Configuration". Within that, you have an attribute called "Path", whose value is "\Package.Variables[User::Quote_ID].Properties[Value]".
I'm not sure what you need to do in your code, but here is an example of one way to go about making changes in that value:
XmlDocument xDoc = new XmlDocument();
xDoc.Load(#"\\MyServer\DataFiles$\...\MyConfigFile.dtsConfig");
XmlNode xFile = xDoc.SelectSingleNode("Configuration");
xFile.Attributes["Path"].Value = xFile.Attributes["Path"].Value.Replace("User::Quote_ID", "newValue");
xDoc.Save(#"\\MyServer\DataFiles$\...\MyConfigFile.dtsConfig");
xDoc = null;
The above example will change \Package.Variables[User::Quote_ID].Properties[Value] to \Package.Variables[newValue].Properties[Value].
Updated Example
This will replace the 77777 value with quote_ID.ToString() (I'm assuming the 55555 is in there) for the first node (for all nodes, remove break;) where the 'Path' is \Package.Variables[User::Quote_ID].Properties[Value].
XmlDocument xDoc = new XmlDocument();
xDoc.Load(#"\\MyServer\DataFiles$\...\MyConfigFile.dtsConfig");
XmlNodeList listOfConfigurationNodes = xDoc.SelectNodes("Configuration");
foreach (XmlNode node in listOfConfigurationNodes)
{
if (node.Attributes["Path"].Value == #"\Package.Variables[User::Quote_ID].Properties[Value]")
{
node.SelectSingleNode("ConfiguredValue").InnerText = quote_ID.ToString();
break;
}
}
xDoc.Save(#"\\MyServer\DataFiles$\...\MyConfigFile.dtsConfig");
xDoc = null;
I am trying to read an XML feed from http://itunes.apple.com/us/rss/topsongs/limit=10/genre=2/xml.
I want to access the fields like this:
<im:price amount="1.29000" currency="USD">$1.29</im:price>
<im:releaseDate label="December 31, 1960">1960-12-31T16:00:00-07:00</im:releaseDate>
Here is what I have done so far:
var xml = "http://itunes.apple.com/us/rss/topsongs/limit=10/genre=2/xml";
XmlDocument doc = new XmlDocument();
doc.Load(xml);
XmlNodeList items = doc.SelectNodes("//entry");
foreach (var item in items) {
// Do something with item.
}
No luck, though. items is null. Why? What am I doing wrong?
You need to create a namespace manager to map the RSS and also the iTunes custom tags namespace URIs to short prefixes (itunes and im in the example below):
var xml = "http://itunes.apple.com/us/rss/topsongs/limit=10/genre=2/xml";
XmlDocument doc = new XmlDocument();
doc.Load(xml);
var namespaceManager = new XmlNamespaceManager(doc.NameTable);
namespaceManager.AddNamespace("itunes", "http://www.w3.org/2005/Atom");
namespaceManager.AddNamespace("im", "http://itunes.apple.com/rss");
XmlNodeList items = doc.SelectNodes("//itunes:entry", namespaceManager);
foreach (XmlNode item in items)
{
var price = item.SelectSingleNode("im:price", namespaceManager);
var releaseDate = item.SelectSingleNode("im:releaseDate", namespaceManager);
if (price != null)
{
Console.WriteLine(price.Attributes["amount"].InnerText);
}
if (releaseDate != null)
{
Console.WriteLine(releaseDate.Attributes["label"].InnerText);
}
}
For that specific feed you should get 10 entries.
It's in the docs as well:
If the XPath expression does not include a prefix, it is assumed that
the namespace URI is the empty namespace. If your XML includes a
default namespace, you must still use the XmlNamespaceManager and add
a prefix and namespace URI to it; otherwise, you will not get any
nodes selected. For more information, see Select Nodes Using XPath
Navigation.
Alternatively you can use a namespace-agnostic XPath (from here):
XmlNodeList items = doc.SelectNodes("//*[local-name() = 'entry']");
Finally, not sure why you said items is null. It cannot be. When running your original code you should get this:
I'm trying to parse XML returned from the Youtue API. The APIcalls work correctly and creates an XmlDocument. I can get an XmlNodeList of the "entry" tags, but I'm not sure how to get the elements inside such as the , , etc...
XmlDocument xmlDoc = youtubeService.GetSearchResults(search.Term, "published", 1, 50);
XmlNodeList listNodes = xmlDoc.GetElementsByTagName("entry");
foreach (XmlNode node in listNodes)
{
//not sure how to get elements in here
}
The XML document schema is shown here: http://code.google.com/apis/youtube/2.0/developers_guide_protocol_understanding_video_feeds.html
I know that node.Attributes is the wrong call, but am not sure what the correct one is?
By the way, if there is a better way (faster, less memory) to do this by serializing it or using linq, I'd be happy to use that instead.
Thanks for any help!
Here some examples reading the XmlDocument. I don't know whats fastest or what needs less memory - but i would prefer Linq To Xml because of its clearness.
XmlDocument xmlDoc = youtubeService.GetSearchResults(search.Term, "published", 1, 50);
XmlNodeList listNodes = xmlDoc.GetElementsByTagName("entry");
foreach (XmlNode node in listNodes)
{
// get child nodes
foreach (XmlNode childNode in node.ChildNodes)
{
}
// get specific child nodes
XPathNavigator navigator = node.CreateNavigator();
XPathNodeIterator iterator = navigator.Select(/* xpath selector according to the elements/attributes you need */);
while (iterator.MoveNext())
{
// f.e. iterator.Current.GetAttribute(), iterator.Current.Name and iterator.Current.Value available here
}
}
and the linq to xml one:
XmlDocument xmlDoc = youtubeService.GetSearchResults(search.Term, "published", 1, 50);
XDocument xDoc = XDocument.Parse(xmlDoc.OuterXml);
var entries = from entry in xDoc.Descendants("entry")
select new
{
Id = entry.Element("id").Value,
Categories = entry.Elements("category").Select(c => c.Value)
};
foreach (var entry in entries)
{
// entry.Id and entry.Categories available here
}
I realise this has been answered and LINQ to XML is what I'd go with but another option would be XPathNavigator. Something like
XPathNavigator xmlNav = xmlDoc.CreateNavigator();
XPathNodeIterator xmlitr = xmlNav.Select("/XPath/expression/here")
while (xmlItr.MoveNext()) ...
The code is off the top of my head so it may be wrong and there may be a better way with XPathNavigator but it should give you the general idea
You could use XSD.exe to generate a class based on the schema provided. Once generated, you could then parse the XML response into the strongly typed class.
string xmlResponse = GetMyYouTubeStuff();
MyYouTubeClass response = null;
XmlHelper<MyYouTubeClass> xmlHelper = new XmlHelper<MyYouTubeClass>();
response = xmlHelper.Deserialize(xmlResponse);
And the class for deserializing it...
public class XmlHelper<T>
{
public T Deserialize(string xml)
{
XmlSerializer xs = new XmlSerializer(typeof(T));
Byte[] byteArray = new UTF8Encoding().GetBytes(xml);
MemoryStream memoryStream = new MemoryStream(byteArray);
XmlTextReader xmlTextReader = new XmlTextReader(memoryStream);
T retObj = (T)xs.Deserialize(xmlTextReader);
return retObj;
}
}
There's also another way here.