Append xml string into Existing xmlfile using c# - c#

I have an xml like this :
<name>
<class>
</class>
</name>
then i want to add the tag like this
<tia:Demographic><Age/><DOB/></tia:Demographic>
in between
<class>
How can we do that .
i am using following code.
XDoc.LoadXml(#"<name><class></class></name>");
XmlDocumentFragment xfrag = XDoc.CreateDocumentFragment();
xfrag.InnerXml = #"<tia:Demographic><Age/><DOB/></tia:Demographic>";
XDoc.DocumentElement.FirstChild.AppendChild(xfrag);
XDoc.Save(#"D:\test.xml");
but it throws an error that tia: not a registered namespace

Register the namespace using a XmlNamespaceManager .

You will need to register a namespace:
class Program
{
static void Main()
{
var xdoc = new XmlDocument();
xdoc.LoadXml(#"<name><class></class></name>");
xdoc.DocumentElement.SetAttribute("xmlns:tia", "http://tia.com");
var node = xdoc.CreateElement("tia", "Demographic", "http://tia.com");
var xfrag = xdoc.CreateDocumentFragment();
xfrag.InnerXml = #"<Age/><DOB/>";
node.AppendChild(xfrag);
xdoc.DocumentElement.FirstChild.AppendChild(node);
xdoc.Save(Console.Out);
}
}

Related

How to change XML element value

I need your help to finish my task also gain some knowledge from it.
I am having XMl like below
<?xml version="1.0" encoding="UTF-8"?>
<spml:batchRequest xmlns:subscriber="urn:abc:names:prov:gw:SUBSCRIBER:3:0" xmlns:spml="urn:abc:names:prov:gw:SPML:2:0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" execution="synchronous" timestamp="true" processing="sequential" onError="exit_commit">
<version>SUBSCRIBER_v30</version>
<request xsi:type="spml:ModifyRequest" returnResultingObject="full">
<version>SUBSCRIBER_v30</version>
<objectclass>Subscriber</objectclass>
<identifier>1234567890</identifier>
<modification name="udm5gData/servingPlmnId[#plmnId='20201']/provisionedData/sessionManagementSubscriptionData[#singleNssai='1-000002']/dnnConfiguration[#dnnId='dj.nmdd']" operation="remove" scope="uniqueTypeMapping" xmlns:subscriber="urn:abc:names:prov:gw:SUBSCRIBER:3:0">
</modification>
</request>
</spml:batchRequest>
Out of this I need to modify the #singleNssai='1-000002' from modification tag Could anyone help me to change.
Something like #singleNssai='2-000001'
I am trying like below
XmlDataDocument doc = new XmlDataDocument();
doc.Load("D:\\soaptemp\\test.xml");
XmlNode singlenssais =
doc.SelectSingleNode("//modification/name/#singleNssai");
if (singlenssais != null)
{
singlenssais.Value = "2-000001"; // Set to new value.
}
Using Xml Linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication40
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XElement modification = doc.Descendants("modification").First();
XAttribute name = modification.Attribute("name");
string strName = (string)name;
strName = strName.Replace("1-000002", "2-000001");
name.SetValue(strName);
}
}
}

How do I generate a SOAP-compatible XML response with correct namespace prefixes?

I'm writing a small web server (HttpListener) which will ultimately run as part of a Windows service and response to SOAP requests from another application.
I've written the code to decode the SOAP request XML and extract the action, process it and get the result, but can't quite get the response XML to be generated correctly.
I've like to avoid generating each element individually since the Types of the response may vary and I don't want to have to code every variant into the web server and would prefer not to have to delve into Reflection and walk the Type structure to output the values. I'd prefer to use something simple like the XmlSerializer Serialize method (which presumably is walking the Type structure), but it's not clear if it has enough control.
The output I'm trying to produce in my test program is:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<GetUsernamesResponse xmlns="http://tempuri.org/">
<GetUsernamesResult xmlns:a="http://schemas.datacontract.org/2004/07/ConsoleApp2"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Results xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<b:string>Kermit.The.Frog</b:string>
<b:string>Miss.Piggy</b:string>
</a:Results>
</GetUsernamesResult>
</GetUsernamesResponse>
</s:Body>
</s:Envelope>
The output I'm getting is:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<GetUsernamesResponse xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://tempuri.org/">
<GetUsernamesResult xmlns:a="http://schemas.datacontract.org/2004/07/ConsoleApp2"
xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays"
xmlns="">
<Results>
<string>Kermit.The.Frog</string>
<string>Miss.Piggy</string>
</Results>
</GetUsernamesResult>
</GetUsernamesResponse>
</s:Body>
</s:Envelope>
This is the current test program:
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApp2
{
public class GetUsernamesResponse
{
public List<string> Results { get; set; }
}
public class GetUsernamesResult : GetUsernamesResponse {}
public class Program
{
private const string ns_t = "http://tempuri.org/";
private const string ns_s = "http://schemas.xmlsoap.org/soap/envelope/";
private const string ns_i = "http://www.w3.org/2001/XMLSchema-instance";
private const string ns_a = "http://schemas.datacontract.org/2004/07/ConsoleApp2";
private const string ns_b = "http://schemas.microsoft.com/2003/10/Serialization/Arrays";
private static void Main(string[] args)
{
var r = new GetUsernamesResult()
{
Results = new List<string>
{
"Kermit.The.Frog",
"Miss.Piggy"
}
};
var ns = new XmlSerializerNamespaces();
ns.Add("i", ns_i);
ns.Add("a", ns_a);
ns.Add("b", ns_b);
var oSerializer = new XmlSerializer(typeof(GetUsernamesResult));
using (var sw = new StringWriter())
{
var xw = XmlWriter.Create(
sw,
new XmlWriterSettings()
{
OmitXmlDeclaration = true,
Indent = true,
ConformanceLevel = ConformanceLevel.Fragment,
NamespaceHandling = NamespaceHandling.OmitDuplicates,
});
xw.WriteStartElement("s", "Envelope", ns_s);
xw.WriteStartElement("s", "Body", ns_s);
xw.WriteStartElement($"GetUsernamesResponse", ns_t);
xw.WriteAttributeString("xmlns", "i", null, ns_i);
oSerializer.Serialize(xw, r, ns);
xw.WriteEndElement();
xw.WriteEndElement();
xw.WriteEndElement();
xw.Close();
Console.WriteLine(sw);
}
Console.ReadKey();
}
}
}
Can this be done with Serialize or do have to do it with Reflection and, effectively, reproduce what the SOAP responder in IIS is already doing?
FYI, I also tried setting up a Type mapping...
var mapping = new SoapReflectionImporter().ImportTypeMapping(typeof(BarcodeProductionGetUsernamesResult));
var oSerializer = new XmlSerializer(mapping);
... but the resultant XML was totally different and, although it didn't produce an error, also didn't decode in the calling application; a null value was returned
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<GetUsernamesResponse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/">
<GetUsernamesResult xmlns:a="http://schemas.datacontract.org/2004/07/ConsoleApp2" xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays" id="id1" xmlns="">
<Results href="#id2" />
</GetUsernamesResult>
<q1:Array id="id2" xmlns:q2="http://www.w3.org/2001/XMLSchema" q1:arrayType="q2:string[2]" xmlns:q1="http://schemas.xmlsoap.org/soap/encoding/">
<Item xmlns="">Kermit.The.Frog</Item>
<Item xmlns="">Miss.Piggy</Item>
</q1:Array>
</GetUsernamesResponse>
</s:Body>
</s:Envelope>
I like to use xml linq. For complicated headers a namespaces I just parse a string to get desired results. See code below :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
MyClass myClass = new MyClass();
XDocument doc = MySerializer<MyClass>.GetXElement(myClass);
}
}
public class MySerializer<T> where T : new()
{
static string xml =
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
" <s:Body>" +
" <GetUsernamesResponse xmlns=\"http://tempuri.org/\">" +
" <GetUsernamesResult xmlns:a=\"http://schemas.datacontract.org/2004/07/ConsoleApp2\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" +
" <a:Results xmlns:b=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">" +
" </a:Results>" +
" </GetUsernamesResult>" +
" </GetUsernamesResponse>" +
" </s:Body>" +
"</s:Envelope>";
public static XDocument GetXElement(T myClass)
{
XDocument doc = XDocument.Parse(xml);
XElement results = doc.Descendants().Where(x => x.Name.LocalName == "Results").FirstOrDefault();
XNamespace ns_b = results.GetNamespaceOfPrefix("b");
StringWriter sWriter = new StringWriter();
XmlWriter xWriter = XmlWriter.Create(sWriter);
XmlSerializerNamespaces ns1 = new XmlSerializerNamespaces();
ns1.Add("b", ns_b.NamespaceName);
XmlSerializer serializer = new XmlSerializer(typeof(T), ns_b.NamespaceName);
serializer.Serialize(xWriter, myClass, ns1);
results.Add(XElement.Parse(sWriter.ToString()));
return doc;
}
}
public class MyClass
{
public string test { get; set; }
}
}

Using xpath select how do I get the value of this element in example?

with this XML
<?xml version="1.0" encoding="UTF-8"?>
<createTransactionResponse xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<refId>999999999</refId>
<messages>
<resultCode>Ok</resultCode>
<message>
<code>I00001</code>
<text>Successful.</text>
</message>
</messages>
<transactionResponse>
<responseCode>1</responseCode>
<authCode>HH1D69</authCode>
<avsResultCode>Y</avsResultCode>
<cvvResultCode>P</cvvResultCode>
<cavvResultCode>2</cavvResultCode>
<transId>2228993425</transId>
<refTransID />
<transHash>916EE7527B17B62F62AA72B4C71F8322</transHash>
<testRequest>0</testRequest>
<accountNumber>XXXX0015</accountNumber>
<accountType>MasterCard</accountType>
<messages>
<message>
<code>1</code>
<description>This transaction has been approved.</description>
</message>
</messages>
<userFields>
<userField>
<name>MerchantDefinedFieldName1</name>
<value>MerchantDefinedFieldValue1</value>
</userField>
<userField>
<name>favorite_color</name>
<value>blue</value>
</userField>
</userFields>
</transactionResponse>
</createTransactionResponse>
I would like to get "resultCode", from here
<messages><resultCode>Ok</resultCode><message>
But the xpath I'm using does not give me the value of resultCode Ok.
What am I doing wrong?
--
static void Main(string[] args)
{
string myXML = #"<?xml version=""1.0"" encoding=""utf-8""?><createTransactionResponse xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns=""AnetApi/xml/v1/schema/AnetApiSchema.xsd""><refId>999999999</refId><messages><resultCode>Ok</resultCode><message><code>I00001</code><text>Successful.</text></message></messages><transactionResponse><responseCode>1</responseCode><authCode>HH1D69</authCode><avsResultCode>Y</avsResultCode><cvvResultCode>P</cvvResultCode><cavvResultCode>2</cavvResultCode><transId>2228993425</transId><refTransID /><transHash>916EE7527B17B62F62AA72B4C71F8322</transHash><testRequest>0</testRequest><accountNumber>XXXX0015</accountNumber><accountType>MasterCard</accountType><messages><message><code>1</code><description>This transaction has been approved.</description></message></messages><userFields><userField><name>MerchantDefinedFieldName1</name><value>MerchantDefinedFieldValue1</value></userField><userField><name>favorite_color</name><value>blue</value></userField></userFields></transactionResponse></createTransactionResponse>";
string myValue = XMLSelect(myXML, "createTransactionResponse/messages/message/resultCode");
//myValue should = "Ok" but it does not :(
}
public static string XMLSelect(string _xmldoc, string _xpath)
{
string returnedValue = string.Empty;
XmlDocument doc = new XmlDocument();
try
{
doc.LoadXml(_xmldoc);
XmlElement root = doc.DocumentElement;
returnedValue = (string)doc.SelectNodes(_xpath)[0].InnerText;
}
catch (Exception ex)
{
return "";
}
return returnedValue;
}
Your first problem is that the XML you originally gave isn't valid. You're masking that by returning "" whenever you encounter an exception, so you don't have any information any more.
So the first thing to do IMO is remove the spurious exception handling:
public static string XMLSelect(string _xmldoc, string _xpath)
{
string returnedValue = string.Empty;
XmlDocument doc = new XmlDocument();
doc.LoadXml(_xmldoc);
XmlElement root = doc.DocumentElement;
return (string)doc.SelectNodes(_xpath)[0].InnerText;
}
Now, the problem with the XPath is that all the elements in your XML are in a namespace of AnetApi/xml/v1/schema/AnetApiSchema.xsd - so you'll probably want an XmlNamespaceManager. It's slightly tricky to separate that properly given the way that you've split the load from the XPath, but for the moment you could just introduce an alias of ns for the right namespace.
Next, your XPath is incorrect in that it looks for message/resultCode, when those two elements are peers. You don't want the message part.
Here's a short but complete program which fixes all those problems:
using System;
using System.Xml;
public class Program
{
static void Main(string[] args)
{
// As per the question
string myXML = "...";
string myValue = XMLSelect(myXML, "ns:createTransactionResponse/ns:messages/ns:resultCode");
Console.WriteLine(myValue);
}
public static string XMLSelect(string _xmldoc, string _xpath)
{
string returnedValue = string.Empty;
XmlDocument doc = new XmlDocument();
doc.LoadXml(_xmldoc);
var nsm = new XmlNamespaceManager(doc.NameTable);
nsm.AddNamespace("ns", "AnetApi/xml/v1/schema/AnetApiSchema.xsd");
XmlElement root = doc.DocumentElement;
return (string)doc.SelectNodes(_xpath, nsm)[0].InnerText;
}
}
If you could use LINQ to XML instead, and simply work on the document instead of passing in the XML text and an XPath selector, it would be simpler:
XDocument doc = XDocument.Parse(xml);
XNamespace ns = "AnetApi/xml/v1/schema/AnetApiSchema.xsd";
string code = (string) doc.Root
.Element(ns + "messages")
.Element(ns + "resultCode");
Console.WriteLine(code);

Reading an XML document with XMLDocument C# 'password' string not returning

I'm trying to read the text in between <keyMaterial></keyMaterial>
I tried using //WLANProfile/MSM/security/sharedKey as the element route, seen in the code below. It refuses to return a value. I have run through the debugger and after the breakpoint at the line: XmlNodeList sharedKeyNodes = wifiProfile.SelectNodes("//WLANProfile/MSM/security/sharedKey");
the SharedKeyNodes object doesn't return a count for. I know it's just a matter of figuring out the element route so I'm not coming here completely hopeless...
System.Xml.XPathNodeList
My XML looks like this:
<?xml version="1.0"?>
<WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
<name>nosignal</name>
<SSIDConfig>
<SSID>
<hex>6E6F7369676E616C</hex>
<name>nosignal</name>
</SSID>
<nonBroadcast>true</nonBroadcast>
</SSIDConfig>
<connectionType>ESS</connectionType>
<connectionMode>auto</connectionMode>
<autoSwitch>false</autoSwitch>
<MSM>
<security>
<authEncryption>
<authentication>WPA2PSK</authentication>
<encryption>AES</encryption>
<useOneX>false</useOneX>
<FIPSMode xmlns="http://www.microsoft.com/networking/WLAN/profile/v2">false</FIPSMode>
</authEncryption>
<sharedKey>
<keyType>passPhrase</keyType>
<protected>true</protected>
<keyMaterial>01000000D</keyMaterial>
</sharedKey>
</security>
</MSM>
</WLANProfile>
[ EDIT with the help of LB the new code looks like this and it WORKS! ]
[ For anyone that is struggling with a similar problem. ]
My Class is:
class ProfileManager
{
public static string readProfile() {
XmlDocument wifiProfile = new XmlDocument();
string path = #"C:\temp\nosignal.xml";
string password = "";
wifiProfile.Load(path);
XmlNamespaceManager mgr = new XmlNamespaceManager(wifiProfile.NameTable);
mgr.AddNamespace("ns", "http://www.microsoft.com/networking/WLAN/profile/v1");
XmlNodeList sharedKeyNodes = wifiProfile.SelectNodes("//ns:WLANProfile/ns:MSM/ns:security/ns:sharedKey", mgr);
foreach (XmlNode itemNode in sharedKeyNodes)
{
XmlNode keyMaterialNode = itemNode.SelectSingleNode("ns:keyMaterial", mgr);
if (keyMaterialNode != null)
{
password = keyMaterialNode.InnerText;
}
}
return password;
}
}
I'm close, but still just a bit stuck. Any help would be appreciated!!! Thank you!
You don't use the default XmlNamespace "http://www.microsoft.com/networking/WLAN/profile/v1"
wifiProfile.Load(path);
XmlNamespaceManager mgr = new XmlNamespaceManager(wifiProfile.NameTable);
mgr.AddNamespace("ns", "http://www.microsoft.com/networking/WLAN/profile/v1");
XmlNodeList sharedKeyNodes = wifiProfile.SelectNodes("//ns:WLANProfile/ns:MSM/ns:security/ns:sharedKey",mgr);

How do I use XML prefixes in C#?

EDIT: I have now published my app: http://pastebin.com/PYAxaTHU
I was trying to make console-based application that returns my temperature.
using System;
using System.Xml;
namespace GetTemp
{
class Program
{
static void Main(string[] args)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(downloadWebPage(
"http://www.andrewmock.com/uploads/example.xml"
));
XmlNamespaceManager man = new XmlNamespaceManager(doc.NameTable);
man.AddNamespace("aws", "www.aws.com/aws");
XmlNode weather = doc.SelectSingleNode("aws:weather", man);
Console.WriteLine(weather.InnerText);
Console.ReadKey(false);
}
}
}
Here is the sample XML:
<aws:weather xmlns:aws="http://www.aws.com/aws">
<aws:api version="2.0"/>
<aws:WebURL>http://weather.weatherbug.com/WA/Kenmore-weather.html?ZCode=Z5546&Units=0&stat=BOTHL</aws:WebURL>
<aws:InputLocationURL>http://weather.weatherbug.com/WA/Kenmore-weather.html?ZCode=Z5546&Units=0</aws:InputLocationURL>
<aws:station requestedID="BOTHL" id="BOTHL" name="Moorlands ES" city="Kenmore" state=" WA" zipcode="98028" country="USA" latitude="47.7383346557617" longitude="-122.230278015137"/>
<aws:current-condition icon="http://deskwx.weatherbug.com/images/Forecast/icons/cond024.gif">Mostly Cloudy</aws:current-condition>
<aws:temp units="°F">40.2</aws:temp>
<aws:rain-today units=""">0</aws:rain-today>
<aws:wind-speed units="mph">0</aws:wind-speed>
<aws:wind-direction>WNW</aws:wind-direction>
<aws:gust-speed units="mph">5</aws:gust-speed>
<aws:gust-direction>NW</aws:gust-direction>
</aws:weather>
I'm just not sure how to use XML prefixes correctly here. What is wrong with this?
OK, so based on this XML from the example:
<aws:weather xmlns:aws="http://www.aws.com/aws">
<aws:api version="2.0"/>
<aws:WebURL>http://weather.weatherbug.com/WA/Kenmore-weather.html?ZCode=Z5546&Units=0&stat=BOTHL</aws:WebURL>
<aws:InputLocationURL>http://weather.weatherbug.com/WA/Kenmore-weather.html?ZCode=Z5546&Units=0</aws:InputLocationURL>
<aws:station requestedID="BOTHL" id="BOTHL" name="Moorlands ES" city="Kenmore" state=" WA" zipcode="98028" country="USA" latitude="47.7383346557617" longitude="-122.230278015137"/>
<aws:current-condition icon="http://deskwx.weatherbug.com/images/Forecast/icons/cond024.gif">Mostly Cloudy</aws:current-condition>
<aws:temp units="°F">40.2</aws:temp>
<aws:rain-today units=""">0</aws:rain-today>
<aws:wind-speed units="mph">0</aws:wind-speed>
<aws:wind-direction>WNW</aws:wind-direction>
<aws:gust-speed units="mph">5</aws:gust-speed>
<aws:gust-direction>NW</aws:gust-direction>
</aws:weather>
You're trying to read out which value?
What's wrong with your code is that your XML namespace is wrong:
You have:
XmlNamespaceManager man = new XmlNamespaceManager(doc.NameTable);
man.AddNamespace("aws", "www.aws.com/aws");
but the XML namespace is: http://www.aws.com/aws
so you should have:
XmlNamespaceManager man = new XmlNamespaceManager(doc.NameTable);
man.AddNamespace("aws", "http://www.aws.com/aws");
So to read out e.g. the temperature, use something like this:
XmlDocument doc = new XmlDocument();
doc.LoadXml(downloadWebPage("http://www.andrewmock.com/uploads/9/1/0/7/9107466/example.xml"));
XmlNamespaceManager man = new XmlNamespaceManager(doc.NameTable);
man.AddNamespace("aws", "http://www.aws.com/aws");
XmlNode temps = doc.SelectSingleNode("/aws:weather/aws:temp", man);
string tempValue = temps.InnerText;
Gives you a value of "40.2" in tempValue
And as Henk Holtermann recommended in his comment - it would be even easier to read this with Linq-to-XML:
XDocument doc = XDocument.Load("http://www.andrewmock.com/uploads/9/1/0/7/9107466/example.xml");
XNamespace aws = "http://www.aws.com/aws";
var weatherNode = doc.Document.Descendants(aws + "weather");
var tempNode = weatherNode.Descendants(aws + "temp").FirstOrDefault();
string tempValue = tempNode.Value;
Of course, this doesn't include any error handling just yet (checking for things like the weatherNode being NULL and stuff like that) - but it gives you an idea.

Categories

Resources