how to edit XML data within SOAP Request using C#? - 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.

Related

Getting innertext of XML node

When i try M Adeel Khalid kode i get nothing, and trying others i get errors. i miss something, but i cant se it. My code look like this. but i get an error on Descendants, Saying "xmlDocument does not contain a definition for descendants" As you can probably see, I'm pretty new to this, so bear with me.
protected void btnRetVare_Click(object sender, EventArgs e)
{
fldRetVare.Visible = true;
try
{
functions func = new functions();
bool exists = func.checForMatch(txtRetVare.Text);
string myNumber = txtRetVare.Text;
if (Page.IsValid)
{
if (!exists)
{
txtRetVare.Text= "Varenummer findes ikke";
}
else
{
XmlDocument xmldoc = new XmlDocument();
//xmldoc.Load(Server.MapPath(map));
xmldoc.LoadXml(Server.MapPath(map));
//var Varenummer2055component = xmldoc.SelectNodes("s/Reservedele/Component[Varenummer/text()='"+txtRetVare+"']/Remarks");
//if (Varenummer2055component.Count == 1)
//{
// var remarks = Varenummer2055component[0].InnerText;
// txtRetBemærkninger.Text = remarks.ToString();
//}
string remarks = (from xml2 in xmldoc.Descendants("Component")
where xml2.Element("Varenummer").Value == txtRetVare.Text
select xml2.Element("Remarks")).FirstOrDefault().Value;
txtRetBemærkninger.Text = remarks;
}
}
You can get it this way.
XDocument xdoc = XDocument.Load(XmlPath);
string remarks = (from xml2 in xdoc.Descendants("Component")
where xml2.Element("Varenummer").Value == "2055"
select xml2.Element("Remarks")).FirstOrDefault().Value;
I've tested this code.
Hope it helps.
Use XPath to select the correct node:
XmlDocument xml = new XmlDocument();
xml.LoadXml(#"
<Reservedele>
<Component>
<Type>Elektronik</Type>
<Art>Wheel</Art>
<Remarks>erter</Remarks>
<Varenummer>2055</Varenummer>
<OprettetAf>jg</OprettetAf>
<Date>26. januar 2017</Date>
</Component>
<Component>
<Type>Forbrugsvarer</Type>
<Art>Bulb</Art>
<Remarks>dfdh</Remarks>
<Varenummer>2055074</Varenummer>
<OprettetAf>jg</OprettetAf>
<Date>27. januar 2017</Date>
</Component>
</Reservedele>");
var Varenummer2055component = xml.SelectNodes("s/Reservedele/Component[Varenummer/text()='2055']/Remarks");
if (Varenummer2055component.Count == 1)
{
var remarks = Varenummer2055component[0].InnerText;
}
I think extension method First of LINQ to XML will be simple enough and fill requirements of your questions.
var document = XDocument.Load(pathTopXmlFile);
var remark =
document.Descendants("Component")
.First(component => component.Element("Varenummer").Value.Equals("2055"))
.Element("Remarks")
.Value;
First method will throw exception if xml doesn't contain element with Varenummer = 2055
In case where there is possibility that given number doesn't exists in the xml file you can use FirstOrDefault extension method and add checking for null
var document = XDocument.Load(pathTopXmlFile);
var component =
document.Descendants("Component")
.FirstOrDefault(comp => comp.Element("Varenummer").Value.Equals("2055"));
var remark = component != null ? component.Element("Remarks").Value : null;
For saving new value you can use same "approach" and after setting new value save it to the same file
var document = XDocument.Load(pathTopXmlFile);
var component =
document.Descendants("Component")
.FirstOrDefault(comp => comp.Element("Varenummer").Value.Equals("2055"));
component.Element("Remarks").Value = newValueFromTextBox;
document.Save(pathTopXmlFile);
One more approach, which will be overkill in your particular case, but can be useful if you use other values of xml. This approach is serialization.
You can create class which represent data of your xml file and then just use serialization for loading and saving data to the file. Examples of XML Serialization

XML node name and attributes are not available

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

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;

How to Linq2Xml a webservice?

I'm calling a WebService with HttpWebRequest.Create method and read it with StreamReader, (below method do this job):
private string ReadWebMethod(string address)
{
var myRequest = (HttpWebRequest)HttpWebRequest.Create(address);
myRequest.Method = "POST";
using (var responseReader = new StreamReader(myRequest.GetResponse().GetResponseStream()))
return responseReader.ReadToEnd();
}
This method works well and output a string like this:
<ArrayOfAppObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://tempuri.org/">
<AppObject>
<Name>MyApp</Name>
<Image>StoreApp.png</Image>
<Version>SM2.1.0</Version>
</AppObject>
</ArrayOfAppObject>
Now I want to have a look in this string, So I use XElemnet and parse the string. (below code):
XElement x = XElement.Parse(ReadWebMethod(address));
Now, When I foreach, x.Elements("AppObject"), it doesnt return any item and skip the foreach.
My foreach is like this:
foreach (var item in x.Elements("AppObject"))
{
listApplication.Add(new AppObject { Image = item.Element("Image").Value, Name = item.Element("Name").Value, Version = item.Element("Version").Value });
}
I create a local string and remove attributes after "ArrayOfAppObject" (xmlns:xsi="htt...)(some where name it xmlnamespace) and test it again, And it works as well and foreach does not skipped!
SO, How can I use the xml with namespace?
use XDocument class
using System.Xml.Linq;
//...
var xml = ReadWebMethod(address);
var xdocument = System.Xml.Linq.XDocument.Parse(xml);
updates
as your XML data define the namespace.. xmlns="http://tempuri.org/"
You must declare full XName with valid namespace. to access each element value
XName theElementName = XName.Get("AppObject", "http://tempuri.org/");
//or alternate way..
XName theElementName = XName.Get("{http://tempuri.org/}AppObject");
here 's sample test method
[TestMethod]
public void ParseXmlElement()
{
XDocument xdoc = XDocument.Parse(this.mockXml);
XName appTag = XName.Get("{http://tempuri.org/}AppObject");
XName nameTag = XName.Get("{http://tempuri.org/}Name");
XName imageTag = XName.Get("{http://tempuri.org/}Image");
XElement objElement = xdoc.Root.Element(appTag);
Assert.IsNotNull(objElement, "<AppObject> not found");
Assert.AreEqual("{http://tempuri.org/}AppObject", objElement.Name);
XElement nameElement = objElement.Element(nameTag);
Assert.IsNotNull(nameElement, "<Name> not found");
Assert.AreEqual("MyApp", nameElement.Value);
XElement imageElement = objElement.Element(imageTag);
Assert.IsNotNull(imageElement, "<Image> not found");
Assert.AreEqual("StoreApp.png", imageElement.Value);
}
using Xml.Linq this way..
[TestMethod]
public void ParseXmlLinq()
{
XDocument xdoc = XDocument.Parse(this.mockXml);
XElement app = xdoc.Root.Elements()
.FirstOrDefault(e => e.Name == XName.Get("AppObject", "http://tempuri.org/"));
Assert.IsNotNull(app, "<AppObject> not found");
XElement img = app.Elements()
.FirstOrDefault(x => x.Name == XName.Get("Image", "http://tempuri.org/"));
Assert.IsNotNull(img, "<Image> not found");
Assert.AreEqual("StoreApp.png", img.Value);
}
Note that I just mock up and parse string from your XML.

How to modify an xml attribute's value?

How can i modify the value of an attribute within an xml loaded using Loadxml()?
I'm trying to update the xml string stored in my db. For that, i used the following code:
XmlDocument doc = new XmlDocument();
doc.LoadXml(project.ProjectData);
XmlNodeList pNodes = doc.SelectNodes("project");
foreach (XmlNode pNode in pNodes)
{
XmlAttribute lPDAttribute = pNode.Attributes["lastPubDate"];
if (lPDAttribute != null)
{
string currentValue = lPDAttribute.Value;
if (string.IsNullOrEmpty(currentValue))
{
lPDAttribute.Value = project.PublishDate.ToString();
}
}
}
What should i do to save the updated attribute within my current xml? Please help.
I think you should add the below code line
project.ProjectData = doc.InnerXml
you can store doc.InnerXml as a string in your db

Categories

Resources