Modfiying Xml using C# - c#

I have an xml
<PolicyHdr>
<PolicyHdrData>
<ID>123</ID>
</PolicyHdrData>
</PolicyHdr>
<Role>
<RoleData>
<DisplayFieldName>Payor</DisplayFieldName>
</RoleData>
</Role>
<PolicyCovHdr>
<PolicyCovHdrData>
<ID>000</ID>
<PolicyHdrID>123</PolicyHdrID>
</PolicyCovHdrData>
</PolicyCovHdr>
<Role>
<RoleData>
<DisplayFieldName>Insured</DisplayFieldName>
</RoleData>
</Role>
I need to modify this xml such that the PolicyCovHdr comes as child node of PolicyHDr where the ID node under PolicyHdr is equal to the PolicyHdrID under POlicyCovHDr.
Also the Role Nodes , whenever the DisplayFieldName is Payor it should be child of PolicyHdr and of the DisplayFieldName is Insure it should be the child node of PolicyCovHdr
So the final xml should look something like this:-
<PolicyHdr>
<PolicyHdrData>
<ID>123</ID>
<Role>
<RoleData>
<DisplayFieldName>Payor</DisplayFieldName>
</RoleData>
</Role>
</PolicyHdrData>
<PolicyCovHdr>
<PolicyCovHdrData>
<ID>000</ID>
<PolicyHdrID>123</PolicyHdrID>
<Role>
<RoleData>
<DisplayFieldName>Insured</DisplayFieldName>
</RoleData>
</Role>
</PolicyCovHdrData>
</PolicyCovHdr>
</PolicyHdr>
Could someone help me with some logic which I could use to achieve this xml
Hi sorry I forgot to add my code changes here
string xml1 = "<xml><PolicyHdr><PolicyHdrData><ID>123</ID></PolicyHdrData></PolicyHdr><Role><RoleData><DisplayFieldName>Payor</DisplayFieldName></RoleData></Role><PolicyCovHdr><PolicyCovHdrData><ID>000</ID><PolicyHdrID>123</PolicyHdrID></PolicyCovHdrData></PolicyCovHdr><Role><RoleData><DisplayFieldName>Insured</DisplayFieldName></RoleData></Role></xml>";
XmlDocument test = new XmlDocument();
test.LoadXml(xml1);
XmlNodeList polList = test.SelectNodes("//PolicyHdr/PolicyHdrData");
foreach (XmlNode xn in polList)
{
XmlNode polNode = xn.SelectSingleNode("//PolicyHdr/PolicyHdrData/ID");
XmlNodeList polCovNodeList = test.SelectNodes("//PolicyCovHdr/PolicyCovHdrData");
foreach (XmlNode yn in polCovNodeList)
{
XmlNode polCovPolNode = yn.SelectSingleNode("//PolicyCovHdr/PolicyCovHdrData/PolicyHdrID");
if(polNode.InnerText.ToString().Equals(polCovPolNode.InnerText.ToString()))
{
xn.AppendChild(yn);
}
}
XmlNodeList polRoleList = test.SelectNodes("//Role/RoleData");
foreach (XmlNode zn in polRoleList )
{
XmlNode RoleNode = zn.SelectSingleNode("//Role/RoleData/DisplayFieldName");
if(RoleNode.InnerText.ToString().Equals("Payor"))
{
xn.AppendChild(zn);
}
//Console.WriteLine(RoleNode.InnerText.ToString());
}
Console.WriteLine(xn.OuterXml.ToString());
}
The problem right now I am facing is the complexity is (n^2) and adding the Role node as child to PolicyCovHdr when DisplayFieldName = Insured.
Right now the output looks like this
<PolicyHdrData><ID>123</ID><PolicyCovHdrData><ID>000</ID><PolicyHdrID>123</PolicyHdrID></PolicyCovHdrData><RoleData><DisplayFieldName>Payor</DisplayFieldName></RoleData></PolicyHdrData>
I am still thinking of how to add the Role with DisplayFieldname as Insured as well because of the complexity is already very high

I think that you should use XML Serialization/Deserialization. You can look for example to this question: C# Xml Serialization & Deserialization
At first you can create an object with structure of your input XML, than use XML Deserializer to load the data from XML to this object. After that you can work with the instance of an object and ad some conditions to your code which you need.
You can create another objects which will be representing output XML (depends on the structure as you wrote about it) and in if/else code filling the object with the data you need. Structure of XML will be represented by the structure of the object. Finally you can use XML Serializer to create your XML.
There could probably be better solution, but that should also work.

Related

Failing to read value XML attribute in C#

I am trying to read a file produced by another developer. The file looks something like this. I am trying to read in the value for 'ProfileName', but when I look at the object in memory, I see null for the Value (capital V) attribute. The only place I can see the string "GolfLeague-Dual" is in the outerxml attribute, but I would have to parse through a bunch of just to get it.
<?xml version="1.0"?>
<TopNode>
<ProfileSettings>
<ProfileName value="GolfLeague-Dual" />
</ProfileSettings>
</TopNode>
Here is my code to try to read this:
XmlDocument doc = new XmlDocument();
doc.Load(directory + #"\Settings.xml");
XmlElement root = doc.DocumentElement;
XmlNodeList nodes = root.SelectNodes("//ProfileSettings");
foreach (XmlNode node in nodes) {
Console.WriteLine(node["ProfileName"].Value);
}
Your code is trying to get the inner value of the node, not an attribute called value. Try this instead...
foreach (XmlNode node in nodes) {
Console.WriteLine(node["ProfileName"].Attributes["value"].Value);
}
Here's a working dotnetfiddle...
https://dotnetfiddle.net/pmJKbX

Tricky to read XML from web service C#

I have looked everywhere, and cannot find anything to help me.
I am writing a program that connects to a webservice and then the webservice sends an XML response. After the response is received I have to retrieve certain values from it, but this is where it gets tricky
Here is a snippet of the returned XML:
<?xml version="1.0"?>
<MobilePortalSellingCategoriesHierarchy xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Response xmlns="http://blabla.com/service/">Successful</Response>
<ResponseNumber xmlns="http://blabla.com/service/">0</ResponseNumber>
<SellingCategoriesHierarchy xmlns="http://tym2sell.com/PortalService/">
<Response>Successful</Response>
<ResponseNumber>0</ResponseNumber>
<SellingCategories>
<PortalSellingCategory>
<SellingCategoryId xsi:nil="true" />
<SellingCategoryName>category1</SellingCategoryName>
<DeliveryMethod />
<DeliveryMethodNumber>0</DeliveryMethodNumber>
<SellingCategories>
<PortalSellingCategory>
<SellingCategoryId xsi:nil="true" />
<SellingCategoryName>category1_Item</SellingCategoryName>
<DeliveryMethod />
<DeliveryMethodNumber>0</DeliveryMethodNumber>
<SellingCategories>
<PortalSellingCategory>
<SellingCategoryId>2</SellingCategoryId>
<SellingCategoryName>Item2</SellingCategoryName>
<DeliveryMethod>Display</DeliveryMethod>
<DeliveryMethodNumber>1</DeliveryMethodNumber>
<VoucherValue>0.00</VoucherValue>
<IsVariablePrice>true</IsVariablePrice>
<MinimumVoucherValue>1.00</MinimumVoucherValue>
<MaximumVoucherValue>1000.00</MaximumVoucherValue>
<VoucherValueIncrement>1.00</VoucherValueIncrement>
<AdditionalInputItems>
<PortalAdditionalInputItem>
<InputItemId>-1</InputItemId>
<Label>Value:</Label>
<IsNumericOnly>true</IsNumericOnly>
<MaximumLength>7</MaximumLength>
<Hidden>false</Hidden>
</PortalAdditionalInputItem>
<PortalAdditionalInputItem>
<InputItemId>4</InputItemId>
<Label>Mobile Number</Label>
<IsNumericOnly>true</IsNumericOnly>
<MaximumLength>15</MaximumLength>
<Hidden>false</Hidden>
</PortalAdditionalInputItem>
</AdditionalInputItems>
<TwoStep>false</TwoStep>
<SelectedIcon>SamplePicture</SelectedIcon>
<UnSelectedIcon>SamplePicture</UnSelectedIcon>
This repeats from the SellingCategories node just under Response for a couple of times.
Here is a Snippet of my code where I get the XML as string.
XmlDocument xml = new XmlDocument();
xml.LoadXml(receivedData);
XmlNodeList xnList = xml.SelectNodes("/MobilePortalSellingCategoriesHierarchy");
foreach (XmlNode xn in xnList)
{
string sellingCategoryName = xn["SellingCategoryName"].InnerText;
string SelectedIcon = xn["SelectedIcon"].InnerText;
string UnSelectedIcon = xn["UnSelectedIcon"].InnerText;
richTextBox1.AppendText(string.Format("Name: {0} {1} {2}", sellingCategoryName, SelectedIcon, UnSelectedIcon));
}
I have tried changing xml.SelectNodes("/MobilePortalSellingCategoriesHierarchy");
to
xml.SelectNodes("/MobilePortalSellingCategoriesHierarchy/SellingCategoriesHierarchy/SellingCategories/PortalSellingCategory");
I need to select each SellingCategoryName and list the SellingCategoryName(s) and all the other items underneath it.
I was hoping to get something in the lines of:
Category1
Category1_Item
Item2
SamplePicture
Sample Picture
Mine only reads the First Node and then returns "Successful" to me.
I havve also tried:
XElement root = XElement.Load("FilePath");
var sellingCategoryNames = from PortalSellingCategory in root.Elements("MobilePortalSellingCategoriesHierarchy")
where (string)PortalSellingCategory.Element("SellingCategoriesHierarchy").Element("SellingCategories").Element("PortalSellingCategory") != ""
select PortalSellingCategory;
foreach (var xEle in sellingCategoryNames)
{
richTextBox1.Text = (string)xEle;
}
Any help would be greatly appreciated.
What you are doing with
xml.SelectNodes("/MobilePortalSellingCategoriesHierarchy");
is selecting your root node, which is just one. Thats why you only get one item in your list back. Is the hierarchy important? I can see that PortalSellingCategory can also be inside another PortalSellingCategory. If not maybe you could try the following select:
xml.SelectNodes("//PortalSellingCategory");
This will search for every node named "PortalSellingCategory" in your response, no mather where in the hierarchy it is.
EDIT:
And yes, you should look out for the namespaces, sry for didnt seeing that.
If you like geeting all the nodes with XPath you must create a new NamespaceManager and at it to your selectNodes call:
XmlDocument xml = new XmlDocument();
xml.LoadXml(data);
XmlNamespaceManager ns = new XmlNamespaceManager(xml.NameTable);
ns.AddNamespace("ns", "http://tym2sell.com/PortalService/");
XmlNodeList xnList = xml.SelectNodes("//ns:PortalSellingCategory", ns);
I would use XElement instead of XMLDocument, and then use Linq to query or pick the elmements like: XElement xContact = ....
int contactno = (int?)xContact.Element("command").Element("contactperson").Attribute("contactpersonid") ?? -1;
if (xContact.Element("command").Element("contactperson").Element("name").Element("firstname") != null)
console.writeline(xContact.Element("command").Element("contactperson").Element("name").Element("firstname").Value);
var doc= new XmlDocument();
doc.Load("FilePath");
var nodeList = xml.GetElementsByTagName("PortalSellingCategory");
Hi,
It returns the collection of nodes, and you just have to query it to get needed informations.
Feel free to ask help if needed.
Dimitri.

How to get data from an XML File in C# using XMLDocument class?

Good Evening All, and happy weekend!.
I have been trying all day to understand how to parse my simple XML file so I can understand it enough to write a personal project I want to work on.
I have been reading articles on this site and others but cannot get past where I am :(
My XML Document is ...
<XML>
<User>
<ID>123456789</ID>
<Device>My PC</Device>
</User>
<History>
<CreationTime>27 June 2013</CreationTime>
<UpdatedTime>29 June 2013</UpdatedTime>
<LastUsage>30 June 2013</LastUsage>
<UsageCount>103</UsageCount>
</History>
<Configuration>
<Name>Test Item</Name>
<Details>READ ME</Details>
<Enabled>true</Enabled>
</Configuration>
</XML>
I am trying to get the value in the details element (READ ME). Below is my code
// Start Logging Progress
Console.WriteLine("Test Application - XML Parsing and Creating");
Console.ReadKey();
// Load XML Document
XmlDocument MyDoc = new XmlDocument(); MyDoc.Load(#"E:\MyXML.XML");
// Select Node
XmlNode MyNode = MyDoc.SelectSingleNode("XML/Configuration/Details");
// Output Node Value
Console.WriteLine(String.Concat("Details: ", MyNode.Value));
// Pause
Console.ReadKey();
My console application is running and outputing "Target: " but not giving me the detail within the element.
Can somebody see why this is happening, and perhaps give me advice if I am completely off the wheel? I have no previous knowledge in reading XML files; hence where I am now :)
Thanks! Tom
With the your XPATH expression
// Select Node
XmlNode MyNode = MyDoc.SelectSingleNode("XML/Configuration/Details");
your are selection an element so the type of the MyNode will be XmlElement but the Value of an XmlElement is always null (see on MSDN) so you need to use XmlElement.InnerText or XmlElement.InnerXml isntead.
So the changed your code to
// Output Node Value
Console.WriteLine(String.Concat("Details: ", MyNode.InnerText));
Or you can select the content of an element with using the XPATH text() function, in this case MyNode will be XmlText where you get its value with Value:
// Select Node
XmlNode MyNode = MyDoc.SelectSingleNode("XML/Configuration/Details/text()");
// Output Node Value
Console.WriteLine(String.Concat("Details: ", MyNode.Value));
As a sidenote if you are anyway learning XML manipulation in C# you should check out LINQ to XML which is another/newer way to working with XML in C#.
Just for interest, a little-known "simple" syntax is this:
XmlDocument myDoc = new XmlDocument();
myDoc.Load(#"D:\MyXML.XML");
string details = myDoc["XML"]["Configuration"]["Details"].InnerText;
Note that this (and the XPath approach) could go pop if your XML doesn't conform to the structure you're expecting, so you'd ideally put some validation in there as well.
U can use Xpath library for that (u must include "System.Xml.XPath"):
XmlDocument document = new XmlDocument();
document.Load("MyXml.xml");
XPathNavigator navigator = document.CreateNavigator();
foreach (XPathNavigator nav in navigator.Select("//Details"))
{
Console.WriteLine(nav.Value);
}
the above code iterate over every node called (Details) extracting information and print it.
If you want to retrieve a particular value from an XML file
XmlDocument _LocalInfo_Xml = new XmlDocument();
_LocalInfo_Xml.Load(fileName);
XmlElement _XmlElement;
_XmlElement = _LocalInfo_Xml.GetElementsByTagName("UserId")[0] as XmlElement;
string Value = _XmlElement.InnerText;
Value contains the text value

Read first root node from XML

I work with three kinds of XML files :
Type A:
<?xml version="1.0" encoding="UTF-8"?>
<nfeProc versao="2.00" xmlns="http://www.portalfiscal.inf.br/nfe">
</nfeProc>
Tyepe B:
<?xml version="1.0" encoding="UTF-8"?>
<cancCTe xmlns="http://www.portalfiscal.inf.br/cte" versao="1.04">
</cancCTe>
Type C:]
<?xml version="1.0" encoding="UTF-8"?>
<cteProc xmlns="http://www.portalfiscal.inf.br/cte" versao="1.04">
</cteProc>
I have try with this code to read the first node :
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(#"C:\crruopto\135120068964590_v01.04-procCTe.xml");
XmlNodeList ml = xmlDoc.GetElementsByTagName("*");
XmlElement root = xmlDoc.DocumentElement;
exti = root.ToString();
but dont return anything i want to read the first node , need to know if the file is nfeProc ,canCTE or cteProc
The second question is how i get the value from "value" in the same tag???
Thanks
From this post:
//Root node is the DocumentElement property of XmlDocument
XmlElement root = xmlDoc.DocumentElement
//If you only have the node, you can get the root node by
XmlElement root = xmlNode.OwnerDocument.DocumentElement
I would suggest using XPath. Here's an example where I read in the XML content from a locally stored string and select whatever the first node under the root is:
XmlDocument doc = new XmlDocument();
doc.Load(new StringReader(xml));
XmlNode node = doc.SelectSingleNode("(/*)");
If you aren't required to use the XmlDocument stuff, then Linq is your friend.
XDocument doc = XDocument.Load(#"C:\crruopto\135120068964590_v01.04-procCTe.xml");
XElement first = doc.GetDescendants().FirstOrDefault();
if(first != null)
{
//first.Name will be either nfeProc, canCTE or cteProc.
}
Working with Linq to XML is the newest and most powerful way of working with XML in .NET and offers you a lot more power and flexibility than things like XmlDocument and XmlNode.
Getting the root node is very simple:
XDocument doc = XDocument.Load(#"C:\crruopto\135120068964590_v01.04-procCTe.xml");
Console.WriteLine(doc.Root.Name.ToString());
Once you have constructed an XDocument you don't need to use any LINQ querying or special checking. You simply pull the Root property from the XDocument.
Thanks i have solved this way the first part
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(nomear);
XmlNodeList ml = xmlDoc.GetElementsByTagName("*");
XmlNode primer = xmlDoc.DocumentElement;
exti = primer.Name;
First, to be clear, you're asking about the root element, not the root node.
You can use an XmlReader to avoid having to load large documents completely into memory. See my answer to a how to find the root element at https://stackoverflow.com/a/60642354/1307074.
Second, once the reader is referencing the element, you can use the reader's Name property to get the qualified tag name of the element. You can get the value as a string using the Value property.

Remove all Artist node from an XML file

I have an XmlWriter that contains a xml that looks like the one below, just with a lot more nodes. what's the fastest and best way to remove all the ARTIST node from this xml ?
<CATALOG>
<CD>
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
</CD>
<CD>
<TITLE>Hide your heart</TITLE>
<ARTIST>Bonnie Tyler</ARTIST>
</CD>
</CATALOG>
As long as the file isn't gigabytes XmlDocument should be fine:
XmlDocument XDoc = new XmlDocument();
XDoc.Load(MapPath(#"~\xml\test.xml"));
XmlNodeList Nodes = XDoc.GetElementsByTagName("ARTIST");
foreach (XmlNode Node in Nodes)
Node.ParentNode.RemoveChild(Node);
XDoc.Save(MapPath(#"~\xml\test_out.xml"));
When I tried Steve's solution I received the following error "The element list has changed. The enumeration operation failed to continue". I know it is a bit of a hack but to get around this I used the following:
//Load XML
XmlDocument XDoc = new XmlDocument();
XDoc.Load(MapPath(#"~\xml\test.xml"));
//Get list of offending nodes
XmlNodeList Nodes = XDoc.GetElementsByTagName("ARTIST");
//Loop through the list
while (Nodes.Count != 0) {
foreach (XmlNode Node in Nodes) {
//Remove the offending node
Node.ParentNode.RemoveChild(Node); //<--This line messes with our iteration and forces us to get a new list after each remove
//Stop the loop
break;
}
//Get a refreshed list of offending nodes
Nodes = XDoc.GetElementsByTagName("ARTIST");
}
//Save the document
XDoc.Save(newfile);
I was in a bind and needing something quick and this got the job done.
From the way your question is worded, I'm assuming that you have an XmlWriter that has been used to write an XmlDocument and you want to manipulate what it is going to write before flush is called.
I'm afraid that what you're trying to do may be impossible. The XmlWriter is not meant to manipulate XML before it is written to a destination stream.

Categories

Resources