How to get "Header" node in C# - c#

I'm trying to get the "Header" node from this XML document and to output the XML string to the Textbox in C#, here is the input xml file:
<?xml version="1.0" encoding="UTF-8"?>
<nsSAFT:AuditFile xmlns:nsSAFT="mfp:napz:saa:d1111:declaration:v22">
<nsSAFT:Header>
<nsSAFT:AuditFileVersion>XX</nsSAFT:AuditFileVersion>
<nsSAFT:AuditFileCountry>XX</nsSAFT:AuditFileCountry>
<nsSAFT:AuditFileDateCreated>XXX</nsSAFT:AuditFileDateCreated>
<nsSAFT:SoftwareCompanyName>XXX</nsSAFT:SoftwareCompanyName>
<nsSAFT:SoftwareID>XXXX</nsSAFT:SoftwareID>
<nsSAFT:SoftwareVersion>XXX</nsSAFT:SoftwareVersion>
<nsSAFT:Company>
<nsSAFT:RegistrationNumber>XXX</nsSAFT:RegistrationNumber>
<nsSAFT:Name>XXXX</nsSAFT:Name>
<nsSAFT:Address>
<nsSAFT:StreetName>XXX</nsSAFT:StreetName>
<nsSAFT:City>XXXX</nsSAFT:City>
<nsSAFT:PostalCode>XXX</nsSAFT:PostalCode>
<nsSAFT:Country>XXX</nsSAFT:Country>
</nsSAFT:Address>
<nsSAFT:Contact>
<nsSAFT:ContactPerson>
<nsSAFT:FirstName>XXX</nsSAFT:FirstName>
<nsSAFT:LastName>XXXX</nsSAFT:LastName>
</nsSAFT:ContactPerson>
<nsSAFT:Telephone>XXXXX</nsSAFT:Telephone>
</nsSAFT:Contact>
<nsSAFT:BankAccount>
<nsSAFT:IBANNumber>XXXX</nsSAFT:IBANNumber>
</nsSAFT:BankAccount>
</nsSAFT:Company>
<nsSAFT:DefaultCurrencyCode>XXXX</nsSAFT:DefaultCurrencyCode>
<nsSAFT:SelectionCriteria>
<nsSAFT:SelectionStartDate>XXXX</nsSAFT:SelectionStartDate>
<nsSAFT:SelectionEndDate>XXX</nsSAFT:SelectionEndDate>
</nsSAFT:SelectionCriteria>
<nsSAFT:HeaderComment>X</nsSAFT:HeaderComment>
<nsSAFT:SegmentIndex>X</nsSAFT:SegmentIndex>
<nsSAFT:TotalSegmentsInsequence>X</nsSAFT:TotalSegmentsInsequence>
<nsSAFT:TaxAccountingBasis>XXXX</nsSAFT:TaxAccountingBasis>
</nsSAFT:Header>
</nsSAFT:AuditFile>
Here is how I'm trying to get the "Header" node, with the originalDoc.Element("Header");
XDocument originalDoc = XDocument.Load(fileName);
var list = originalDoc.Element("Header");
string output = list.ToString();
richTextBox1.Text = output;
But in the the debugger, the the list variable is always empty?
The result that I'm expecting:
<nsSAFT:Header>
<nsSAFT:AuditFileVersion>XX</nsSAFT:AuditFileVersion>
<nsSAFT:AuditFileCountry>XX</nsSAFT:AuditFileCountry>
<nsSAFT:AuditFileDateCreated>XXX</nsSAFT:AuditFileDateCreated>
<nsSAFT:SoftwareCompanyName>XXX</nsSAFT:SoftwareCompanyName>
<nsSAFT:SoftwareID>XXXX</nsSAFT:SoftwareID>
<nsSAFT:SoftwareVersion>XXX</nsSAFT:SoftwareVersion>
<nsSAFT:Company>
<nsSAFT:RegistrationNumber>XXX</nsSAFT:RegistrationNumber>
<nsSAFT:Name>XXXX</nsSAFT:Name>
<nsSAFT:Address>
<nsSAFT:StreetName>XXX</nsSAFT:StreetName>
<nsSAFT:City>XXXX</nsSAFT:City>
<nsSAFT:PostalCode>XXX</nsSAFT:PostalCode>
<nsSAFT:Country>XXX</nsSAFT:Country>
</nsSAFT:Address>
<nsSAFT:Contact>
<nsSAFT:ContactPerson>
<nsSAFT:FirstName>XXX</nsSAFT:FirstName>
<nsSAFT:LastName>XXXX</nsSAFT:LastName>
</nsSAFT:ContactPerson>
<nsSAFT:Telephone>XXXXX</nsSAFT:Telephone>
</nsSAFT:Contact>
<nsSAFT:BankAccount>
<nsSAFT:IBANNumber>XXXX</nsSAFT:IBANNumber>
</nsSAFT:BankAccount>
</nsSAFT:Company>
<nsSAFT:DefaultCurrencyCode>XXXX</nsSAFT:DefaultCurrencyCode>
<nsSAFT:SelectionCriteria>
<nsSAFT:SelectionStartDate>XXXX</nsSAFT:SelectionStartDate>
<nsSAFT:SelectionEndDate>XXX</nsSAFT:SelectionEndDate>
</nsSAFT:SelectionCriteria>
<nsSAFT:HeaderComment>X</nsSAFT:HeaderComment>
<nsSAFT:SegmentIndex>X</nsSAFT:SegmentIndex>
<nsSAFT:TotalSegmentsInsequence>X</nsSAFT:TotalSegmentsInsequence>
<nsSAFT:TaxAccountingBasis>XXXX</nsSAFT:TaxAccountingBasis>
</nsSAFT:Header>

Please try the following solution.
As #RobertHarvey pointed out, it was a need to add namespace handling.
c#
void Main()
{
const string inputFile = #"e:\Temp\eXtreme.xml";
XDocument xdoc = XDocument.Load(inputFile);
XNamespace ns = xdoc.Root.GetNamespaceOfPrefix("nsSAFT");
var header = xdoc.Descendants(ns + "Header").FirstOrDefault();
string output = header.ToString();
}

Related

LINQ to read XML String and put into a variable

I am trying to read XML using LINQ. Previously I use XMLDocument to read but it gives an error and someone on StackOverflow encourage me to use LINQ.
Below is the code i previously used for the XMLDocument
string soapmessage = #"<?xml version=""1.0"" encoding=""UTF - 8""?>" + "\n" + response.Content;
XmlDocument xml = new XmlDocument();
xml.LoadXml(soapmessage); //loading soap message as string
XmlNamespaceManager manager = new XmlNamespaceManager(xml.NameTable);
manager.AddNamespace("d", "http://tempuri.org/");
manager.AddNamespace("bhr", "http://52.187.127.196:5000/api/gsowebservice.asmx");
XmlNodeList xnList = xml.SelectNodes("//bhr:FourMonthsAhead1Response", manager);
int nodes = xnList.Count;
string Status = xnList[0]["FourMonthsAhead1Result"]["PlantForecastIntervals"]["PlantForecastIntervalNode"]["IntervalStartTime"].InnerText;
Console.WriteLine(Status);
Console.ReadLine();
I am trying to get the <IntervalStartTime> from the first <PlantForecastIntervalNode> into a datetime variable;
Below attaced the XML im trying read:
Below is some of the XML code. I can't paste it here because the code is 2322 lines long so I shortened the code to this.
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<s:Body>
<FourMonthsAhead1Response xmlns="http://tempuri.org/">
<FourMonthsAhead1Result xmlns="LSS.solar.webservice">
<PlantDescription xmlns="http://base.datacontract">*PlantName*</PlantDescription>
<PlantForecastIntervalsCount xmlns="http://base.datacontract">2976</PlantForecastIntervalsCount>
<ForecastStartDate xmlns="http://base.datacontract">2021-10-08T13:35:55.912612</ForecastStartDate>
<ForecastEndDate xmlns="http://base.datacontract">2021-10-08T13:35:55.9126123</ForecastEndDate>
<PlantForecastIntervals xmlns="http://base.datacontract">
<PlantForecastIntervalNode>
<IntervalStartTime>2021-10-01T00:00:00</IntervalStartTime>
<IntervalEndTime>2021-10-01T00:15:00</IntervalEndTime>
<IntervalLength>15</IntervalLength>
<ForecastResultParameter>FourMonthsAhead1</ForecastResultParameter>
<ForecastValue>0</ForecastValue>
<ValueUnit>MW</ValueUnit>
</PlantForecastIntervalNode>
<PlantForecastIntervalNode>
<IntervalStartTime>2021-10-01T00:15:00</IntervalStartTime>
<IntervalEndTime>2021-10-01T00:30:00</IntervalEndTime>
<IntervalLength>15</IntervalLength>
<ForecastResultParameter>FourMonthsAhead1</ForecastResultParameter>
<ForecastValue>0</ForecastValue>
<ValueUnit>MW</ValueUnit>
</PlantForecastIntervalNode>
</PlantForecastIntervals>
</FourMonthsAhead1Result>
</FourMonthsAhead1Response>
</s:Body>
</s:Envelope>
Update
After exploring other threads on StackOverflow I come up with this line below but receive another error of System.UriFormatException: 'Invalid URI: The Uri string is too long.':
XDocument xdoc = XDocument.Load(soapmessage);
var ids = xdoc.Element("FourMonthsAhead1Result")
.Elements("PlantForecastIntervals")
.Elements("<PlantForecastIntervalNode>")
.Select(item => item.Element("IntervalStartTime").Value);
Console.WriteLine(ids);
Try this using LINQ
var response = File.ReadAllText("XMLFile1.xml");
var xe = XElement.Parse(response);
XNamespace ns = "http://base.datacontract";
var obj = xe.Descendants(ns + "PlantForecastIntervals")
.Descendants(ns + "PlantForecastIntervalNode")
.Select(x => x.Element(ns + "IntervalStartTime").Value);
Console.WriteLine(obj);
Look at below solution,
var xmlRead = File.ReadAllText(#"XMLFile1.xml"); /// Add your xml file path
var xElement = XElement.Parse(xmlRead);
XNamespace xNamespace = "http://base.datacontract";
var obj = xElement.Descendants(xNamespace + "PlantForecastIntervals")
.Descendants(xNamespace + "PlantForecastIntervalNode")
.Select(x => x.Element(xNamespace + "IntervalStartTime").Value);
string[] dateTime = obj.ToArray();
foreach (string x in dateTime)
{
Console.WriteLine(x.ToString()); /// it will print time from all IntervalStartTime tags
}

Update XML file with C#

I have a xml file:
<?xml version="1.0" encoding="utf-8"?>
<ApplicationConfiguration xmlns="http://test.org/SDK/Configuration.xsd">
<ApplicationName>
<ApplicationUri>123</ApplicationUri>
<ApplicationUri>456</ApplicationUri>
</ApplicationName>
</ApplicationConfiguration>
What I want is set the value of ApplicationUri from 456 to 789 in C# code.
I wrote this code:
string docaddress = "testfile.xml";
XDocument doc = XDocument.Load(docaddress);
doc.Element("ApplicationConfiguration")
.Elements("ApplicationName").FirstOrDefault()
.SetElementValue("ApplicationUri", "789");
doc.Save(docaddress);
The problems are:
There is no error while running. I think the element ApplicationConfiguration is not correct. But when I delete the line xmlns=... from the xml file, it runs normally
The value 789 is replaced with 123, but not 456 as I want (same element name)
Can you tell me how to fix those problems?
Hello and welcome to Stack Overflow!
The xmlns attribute on the ApplicationConfiguration element makes that the root.
So you get the root first. Then you replace the values of each descendant, selecting locally by name with the element name you want. something like this:
string docaddress = "C:\\temp\\testfile.xml";
XDocument doc = XDocument.Load(docaddress);
var root = doc.Root;
var descendants = root.Descendants();
var these = root.Descendants().Where(p => p.Name.LocalName == "ApplicationUri");
foreach (var elem in these)
{
elem.Value = "789";
}
doc.Save(docaddress);
I added namespace to your code :
string docaddress = "testfile.xml";
XDocument doc = XDocument.Load(docaddress);
XNamespace ns = doc.Root.GetDefaultNamespace();
doc.Element(ns + "ApplicationConfiguration")
.Elements(ns + "ApplicationName").FirstOrDefault()
.SetElementValue(ns + "ApplicationUri", "789");
doc.Save(docaddress);
IMHO, here is an easiest method.
It is taking care of the XML default namespace.
No loops. Set based approach.
c#
void Main()
{
const string fileName = #"e:\temp\hala.xml";
const string searchFor = "456";
const string replaceWith = "789";
XDocument doc = XDocument.Load(fileName);
XNamespace ns = doc.Root.GetDefaultNamespace();
// step #1: find element based on the search value
XElement xmlFragment = doc.Descendants(ns + "ApplicationUri")
.Where(d => d.Value.Equals(searchFor)).FirstOrDefault();
// step #2: if found, set its value
if(xmlFragment != null)
xmlFragment.SetValue(replaceWith);
doc.Save(fileName);
}

Select single node

From the following xml:
<response>
<content>
<Result xmlns="http://www.test.com/nav/webservices/types">
<Name>Test</Name>
</Result>
</content>
<status>ok</status>
</response>
I am trying to get the value of the Name element the following way but that does not work:
private static void Main()
{
var response = new XmlDocument();
response.Load("Response.xml");
var namespaceManager = new XmlNamespaceManager(response.NameTable);
namespaceManager.AddNamespace("ns", "http://www.test.com/nav/webservices/types");
Console.WriteLine(response.SelectSingleNode("/response/content/Result/Name", namespaceManager).InnerXml);
}
How can I select the Name element?
Your code would have worked just fineif the Xml had defined the namespace with a "ns:" prefix.
But in this case, the namespace is given without any prefix, which sets the default namespace for everything in the Result tag to ".../webservice/types".
To reflect this, you need to modify the Xpath, and tell the XmlDocument that the nodes you are looking for under Resultare in the webservice/types namespace. So your query will look like this:
Console.WriteLine(response.SelectSingleNode(#"/response/content/ns:Result/ns:Name", namespaceManager).InnerXml);
For getting directly the text value of a node there is a text() function, if used in the query it would look like:
/response/content/Result/Name/text()
Try this:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.InnerXml = "<response><content><Result xmlns=\"http://www.test.com/nav/webservices/types\"><Name>Test</Name></Result></content><status>ok</status>";
string elementValue = String.Empty;
if (xmlDoc != null)
{
xNode = xmlDoc.SelectSingleNode("/Result");
xNodeList = xNode.ChildNodes;
foreach (XmlNode node in xNodeList)
{
elementValue = node.InnerText;
}
}

Loop through XML document using XPathNavigator

I have the below XML, and I am trying to write values to a CSV file. I am however not sure how to proceed further, with everything I've tried throwing errors. The below returns:"Expression must evaluate to a node-set". Any assistance is appreciated.
XML:
<?xml version="1.0" encoding="UTF-8"?>
<Envelope>
<Body>
<RESULT>
<SUCCESS>TRUE</SUCCESS>
<Mailing>
<MailingId>9285984</MailingId>
<ReportId>362040252</ReportId>
<ScheduledTS>2014-08-22 11:44:33.0</ScheduledTS>
<MailingName>305_ENDS</MailingName>
</Mailing>
<Mailing>
<MailingId>9278770</MailingId>
<ReportId>361956135</ReportId>
<ScheduledTS>2014-08-22 09:15:00.0</ScheduledTS>
<MailingName>141_TSI</MailingName>
<Visibility>Shared</Visibility>
</Mailing>
<Mailing>
<MailingId>9286460</MailingId>
<ReportId>362043622</ReportId>
<ScheduledTS>2014-08-22 12:57:30.0</ScheduledTS>
<MailingName>301_BRANDREP</MailingName>
</Mailing>
</RESULT>
</Body>
</Envelope>
C#:
xpathDoc = HttpHelper.HttpStream(xmlReq, sessionid);
XPathNavigator nav = xpathDoc.CreateNavigator();
XPathNodeIterator xmlIterator = nav.Select("/Envelope/Body/RESULT/");
var csv = new StringBuilder();
filePath = "C:\Campaigns.csv";
foreach (XPathNavigator node in xmlIterator)
{
string MailingId = node.SelectSingleNode("MailingId").Value;
string ReportId = node.SelectSingleNode("ReportId").Value;
string ScheduledTS = node.SelectSingleNode("ScheduledTS").Value;
string MailingName = node.SelectSingleNode("MailingName").Value;
string newLine = string.Format("{0},{1},{2},{3},{4}", MailingId, ReportId, ScheduledTS, MailingName, Environment.NewLine);
csv.Append(newLine);
}
File.WriteAllText(filePath, csv.ToString());
Well, you can try following approach:
foreach (XPathNavigator node in nav.Select("/Envelope/Body/RESULT/Mailing"))
{
string MailingId = node.SelectSingleNode("./MailingId").Value;
// and so on
Note: it should be exactly Mailing not RESULT as in your query, and should not ends with /
Change XPathNavigator node in nav.Select("/Envelope/Body/RESULT/") to XPathNavigator node in nav.Select("/Envelope/Body/RESULT/Mailing") and then use e.g. string MailingId = node.SelectSingleNode("MailingId").Value;.

C# XML How to retrive innerText of field by attribute?

Here is the XML sample:
<?xml version="1.0" ?>
<XMLScreen xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<CX>80</CX>
<CY>24</CY>
<Formatted>true</Formatted>
<Field>
<Location position="1" left="1" top="0" length="69" />
<Attributes Base="226" Protected="false" FieldType="High" />
*SDC SCHEDULING CATEGORY UPDATE
</Field>
</XMLScreen>
I want to retrive the Inner text of each field based on its Location position.
What I have so far is:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(myEm.CurrentScreenXML.GetXMLText());
XmlNodeList fields = xmlDoc.GetElementsByTagName("Field");
MessageBox.Show("Field spot: " + i + " Contains: " + fields[i].InnerText);
And I want to be able to just extract the inner text of the field by passing in a number of the location position. So if I say foo[i] I want to be able to get the innertext
*SDC SCHEDULING CATEGORY UPDATE
You should use a xpath search query :
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
int nodeId = 4;
XmlNode node = xmlDoc.SelectSingleNode(String.Format(#"//Location[#position='{0}']", nodeId));
if (node != null)
{
String field = node.ParentNode.InnerText;
}
Something like that, with XDocument instead of XmlDocument (well, if you're not in .net 3.5 or higher, we'll have a problem).
private string GetTextByLocationId(XDocument document, int id)
{
var field = document.Descendants("Field").FirstOrDefault(m => m.Element("Location").Attribute("position").Value == id.ToString());
if (field == null) return null;
return field.Value;
}
and usage
var xDocument = XDocument.Load(<pathToXmlFile or XmlReader or string or ...>);
var result = GetTextByLocationId(xDocument, 1);
EDIT
or if you want a dictionary with :key = position / value = text
private static Dictionary<int, string> ParseLocationAndText(XDocument document)
{
var fields = document.Descendants("Field");
return fields.ToDictionary(
f => Convert.ToInt32(f.Element("Location").Attribute("position").Value),
f => f.Value);
}
Try,
XElement root = XElement.Parse(myEm.CurrentScreenXML.GetXMLText());
XElement field = root.XPathSelectElement(
string.Format("Field[Location/#position='{0}']", 1));
string text = field.Value;
You will need to use the following using to use XPath with XElements.
using System.Xml.XPath;

Categories

Resources