XML node name and attributes are not available - c#

I have the following XML structure:
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<values>
<bool key="Chapter_1.Boolean1.value">true</bool>
<string key="Chapter_1.Text1.value">abc</string>
<string key="Chapter_1.Text2.value">Inspection done (2)</string>
<number key="Chapter_1.Number1.value">128</number>
<number key="Chapter_1.Number2.value">34539718</number>
<number key="Chapter_1.Number3.value">3</number>
<datetime key="Chapter_2.Chapter_2_1.DateTime1.value">2020-06-02T09:00:00+03:00</datetime>
<datetime key="Chapter_2.Chapter_2_1.DateTime2.value">2016-02-05T00:00:00+02:00</datetime>
<string key="Chapter_3.Text4.value">52</string>
<string key="Chapter_3.Text5.value">22</string>
<number key="Chapter_3.Number6.value">34539718</number>
</values>
and the following C# code:
var settings = new XmlReaderSettings();
settings.ConformanceLevel = ConformanceLevel.Auto;
settings.IgnoreWhitespace = true;
settings.IgnoreComments = true;
using (var xmlReader = new XmlTextReader(xmlFilePath))
{
while (xmlReader.Read())
{
var nodeName = xmlReader.Name;
var attrName = xmlReader.GetAttribute("key");
}
}
The problem is that the node name is empty and there are no attributes for the following keys:
Chapter_1.Text1.value
Chapter_1.Number1.value
Chapter_3.Text5.value
Anyone has any idea what could be the problem?

The code worked well here, I was able to access all xml tags and attributes.
Maybe you're confused because at each xmlReader.Read() it reads only one part of the tag. So to read all the tag with key "Chapter_1.Text1.value", first it reads a tag with name string and key "Chapter_1.Text1.value", then it reads something without a name, without a attribute, but with value "abc" and then it reads the tag closing with name string, but no attribute and no value.

It would be easier to use Xml to Linq :
var xml = XDocument.Load(__PATH_TO_XML__);
var values = xml.XPathSelectElements("/values/*")
.Select(x => new
{
Type = x.Name,
Key = x.Attribute("key"),
Value = x.Value
});

If you want to read the value as well, try this
using (var xmlReader = new XmlTextReader(#"yourxmlfile"))
{
while (xmlReader.Read())
{
if (xmlReader.NodeType == XmlNodeType.Element)
{
var nodeName = xmlReader.Name;
var attrName = xmlReader.GetAttribute("key");
Console.WriteLine(nodeName);
Console.WriteLine(attrName);
}
if (xmlReader.NodeType==XmlNodeType.Text)
{
Console.WriteLine(xmlReader.Value);
}
}
}

Related

Writing XML records one at a time

I am working with a very large data set so need to write records to an xml file one at a time.
I have tried this code:
using (FileStream retryFile = System.IO.File.Create(filePath))
{
var emptyNamespaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
var ser = new XmlSerializer(typeof(Record));
foreach(var item in veryLargeEnumerable)
{
ser.Serialize(retryFile, item, emptyNamespaces);
}
}
This writes the record but between every record it adds:
<?xml version="1.0"?>
When I try to read the file I get invalid format error.
How can I serialize objects one at a time to XML?
The code shown in your question generates an invalid xml hierarchy;
it doesn't contain a single root element, as each <Record> gets written at the root level, eg.:
<?xml version="1.0"?>
<Record>
<Name>foo</Name>
</Record><?xml version="1.0"?>
<Record>
<Name>bar</Name>
</Record><?xml version="1.0"?>
<Record>
<Name>baz</Name>
</Record>
You'll have to construct a single root element first.
Use an XmlWriter to do so, and then use that same XmlWriter as target to serialize the records into.
using (FileStream retryFile = System.IO.File.Create(filePath))
using (var xmlWriter = XmlWriter.Create(retryFile))
{
xmlWriter.WriteStartElement("Records");
var emptyNamespaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
var ser = new XmlSerializer(typeof(Record));
/* Your loop goes here. */
ser.Serialize(xmlWriter, new Record { Name = "foo" }, emptyNamespaces);
ser.Serialize(xmlWriter, new Record { Name = "bar" }, emptyNamespaces);
ser.Serialize(xmlWriter, new Record { Name = "baz" }, emptyNamespaces);
xmlWriter.WriteEndElement();
}
public class Record
{
public string Name {get; set; }
}
The xml wil then look like below, having a single root element <Records> containing the <Record> child elements.
<?xml version="1.0" encoding="utf-8"?>
<Records>
<Record><Name>foo</Name></Record>
<Record><Name>bar</Name></Record>
<Record><Name>baz</Name></Record>
</Records>

How to get node values in XML file using c#

I have an XML file, in this XML you can see the RESPONSE_DATA tag. This tag have some more inner tags. I need to get all the values inside PERSON_DATA tags. Also i need to get all the other value in below xml file.
<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n
<HUMAN_VERIFICATION xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RESPONSE_DATA>
<RESPONSE_STATUS>
<ERROR>100</ERROR>
<MESSAGE>successful</MESSAGE>
</RESPONSE_STATUS>
<CONTACT_NUMBER>3120202456011</CONTACT_NUMBER>
<PERSON_DATA>
<NAME>Alex</NAME>
<DATE_OF_BIRTH>10-9-1982</DATE_OF_BIRTH>
<BIRTH_PLACE>Washington</BIRTH_PLACE>
<EXPIRY>2020-12-15</EXPIRY>
</PERSON_DATA>
<CARD_TYPE>idcard</CARD_TYPE>
</RESPONSE_DATA>
</HUMAN_VERIFICATION>
I prefer using Linq to Xml.
var results = doc.Descendants("PERSON_DATA") // Flatten the hierarchy and look for PERSON_DATA
.Select(x=> new
{
NAME = (string)x.Element("NAME"),
DATE_OF_BIRTH = (string)x.Element("DATE_OF_BIRTH"),
BIRTH_PLACE = (string)x.Element("BIRTH_PLACE"),
EXPIRY = (string)x.Element("EXPIRY"),
});
Check the Demo
You can try this code it may be helpful for you.
XmlDocument newdoc = new XmlDocument();
newdoc.InnerXml = " <?xml version=\"1.0\" encoding=\"utf-16\"?><HUMAN_VERIFICATION><RESPONSE_DATA><RESPONSE_STATUS><ERR>100</ERROR><MESSAGE>successful</MESSAGE></RESPONSE_STATUS><CONTACT_NUMBER>3120202456011</ CONTACT _NUMBER><PERSON_DATA><NAME>Alex</NAME><DATE_OF_BIRTH>10-9-1982</DATE_OF_BIRTH><BIRTH_PLACE>Washington</BIRTH_PLACE><EXPIRY>2020-12-15</EXPIRY></PERSON_DATA><CARD_TYPE>idcard</CARD_TYPE></RESPONSE_DATA></HUMAN_VERIFICATION>";
var selectnode = "HUMAN_VERIFICATION/RESPONSE_DATA/PERSON_DATA";
var nodes = newdoc.SelectNodes(selectnode);
foreach (XmlNode nod in nodes)
{
string name = nod["NAME" ].InnerText;
string dob = nod["DATE_OF_BIRTH"].InnerText;
string place = nod["BIRTH_PLACE" ].InnerText;
string expiry = nod["EXPIRY" ].InnerText;
Console.WriteLine("Person: {0} {1} {2} {3}", name, dob, place, expiry);
}
It's really easy and intuitive with System.Xml.Linq.
var xml = "<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n<HUMAN_VERIFICATION xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\r\n <RESPONSE_DATA>\r\n <RESPONSE_STATUS>\r\n <ERROR>100</ERROR>\r\n <MESSAGE>successful</MESSAGE>\r\n </RESPONSE_STATUS>\r\n <CONTACT_NUMBER>3120202456011</CONTACT_NUMBER>\r\n <PERSON_DATA>\r\n <NAME>Alex</NAME>\r\n <DATE_OF_BIRTH>10-9-1982</DATE_OF_BIRTH>\r\n <BIRTH_PLACE>Washington</BIRTH_PLACE>\r\n <EXPIRY>2020-12-15</EXPIRY>\r\n </PERSON_DATA>\r\n <CARD_TYPE>idcard</CARD_TYPE>\r\n </RESPONSE_DATA>\r\n</HUMAN_VERIFICATION>";
var document = XDocument.Parse(xml);
var name = document.Element("HUMAN_VERIFICATION").Element("RESPONSE_DATA").Element("PERSON_DATA").Element("NAME").Value;
OR
var personData = document.Element("HUMAN_VERIFICATION").Element("RESPONSE_DATA").Element("PERSON_DATA").Elements().ToDictionary(e => e.Name.ToString(), e => e.Value);

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;
}
}

Duplicate existing element in xml in C#

Please I would like to clone element prijemkaItem from this xml:
The element prijemkaItem is got by this function:
XElement doc = XElement.Load("input.xml");
XmlReader reader = XmlReader.Create("input.xml");
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
if (reader.Name == "pri:prijemkaItem")
elementPrijemkaItem = XElement.ReadFrom(reader) as XElement;
break;
}
}
reader.Close()
I would like to put this element behind itself. Please any idea, how can I do this?
Thanks for any advice.
Assuming for simplicity that your Xml structure is the following:
<?xml version="1.0" encoding="utf-8"?>
<dat:dataPack xmlns:dat="datNamespace">
<dat:dataPackItem>
<pri:prijemka xmlns:pri="priNamespace">
<othernode></othernode>
</pri:prijemka>
</dat:dataPackItem>
</dat:dataPack>
If you want to duplicate the pri:prijemka node you can use Linq to Xml:
//using System.Xml.Linq;
//load the xml file
Document doc = XDocument.Load( "D:\\input.xml" );
//get the "dat" namespace
var datNamespace = doc.Root.GetNamespaceOfPrefix( "dat" );
//get "dat:dataPackItem" node
var dataPackItemNode = doc.Root.Element( datNamespace + "dataPackItem" );
//since you don't know the "pri" namespace you can do:
var prijemkaNode = dataPackItemNode.Descendants( )
.Where(x => x.Name.LocalName == "prijemka")
.FirstOrDefault();
//add it to the "dat:dataPackItem" node
dataPackItemNode.Add( prijemkaNode );
//save the xml file
doc.Save( "D:\\input.xml" );
The result is:
<?xml version="1.0" encoding="utf-8"?>
<dat:dataPack xmlns:dat="datNamespace">
<dat:dataPackItem>
<pri:prijemka xmlns:pri="priNamespace">
<othernode></othernode>
</pri:prijemka>
<pri:prijemka xmlns:pri="priNamespace">
<othernode></othernode>
</pri:prijemka>
</dat:dataPackItem>
</dat:dataPack>

how to edit XML data within SOAP Request using C#?

I would like to edit xml data for one element with in SOAP request in order to send unique SOAP requests.
Following is the example request
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"xmlns:web="http://webservice/">
<soapenv:Header/>
<soapenv:Body>
<web:ca>
<type1>
<ad>2013-07-19</ad>
<name>abcd 13071502</name>
<taker>
<taker>TEST</taker>
<emailAddress>test#test.com</emailAddress>
<name>nameTest</name>
<phoneNo>007007007</phoneNo>
<takerUid>1234</takerUid>
</taker>
</type1>
<type2>4</type2>
<type3>peace</type3>
<type4>test</type4>
</web:ca>
</soapenv:Body>
</soapenv:Envelope>
I would like to change "name" element value from "abcd 13071502" to "abcd ". I was able to extract data from "name" element and edit the value by using following code in C#
System.Xml.XmlTextReader xr = new XmlTextReader(#filePath);
while (xr.Read())
{
if (xr.LocalName == "name")
{
xr.Read();
currentNameValue = xr.Value;
int cnvLen = currentNameValue.Length;
string cnvWOdate = currentNameValue.Substring(0, cnvLen-8);
string newNameValue = cnvWOdate+currTimeDate;
break;
}
}
However, I couldn't figure out how to edit the value and save the file. Any help would be appreciated. Thank you.
Use the XmlDocument class instead of the XmlTextReader class.
System.Xml.XmlDocument xd = new XmlDocument();
xd.Load(#"filepath");
foreach(XmlNode nameNode in xd.GetElementsByTagName("name"))
{
if(nameNode.ParentNode.Name == "type1")
{
string currentNameValue = nameNode.InnerText;
int cnvLen = currentNameValue.Length;
string cnvWOdate = currentNameValue.Substring(0,cnvLen-8);
string newNameValue = cnvWOdate+currTimeDate;
nameNode.InnerText = newNameValue;
}
}
xd.Save(#"newFilePath");
XmlDocument doc = new XmlDocument();
doc.Load("file path");
XmlNode nameNode = doc.SelectSingleNode("/Envelope/Body/ca/type1/name");
string currentNameValue = nameNode != null ? nameNode.InnerText : "name not exist";
int cnvLen = currentNameValue.Length;
string cnvWOdate = currentNameValue.Substring(0, cnvLen-8);
string newNameValue = cnvWOdate+currTimeDate;
nameNode.InnerText = newNameValue; //set new value to tag
To get Value or InnerText of a node, you will have to make sure the node exist. The line string currentNameValue has the format like this:
var variable = condition ? A : B;
It's basically saying that if condition is true, then variable equals A, otherwise, variable equals B.

Categories

Resources