I have a xNode made by JSON.
C# code:
Class class = new Class();
class.ComboBoxChecked = Class.ComboBoxChecked;
class.RadioButtonChecked = Class.RadioButtonChecked;
string test = JsonConvert.SerializeObject(class);
XNode node = JsonConvert.DeserializeXNode(test, "Root");
XML:
<Root>
<RadioButtonChecked>1</RadioButtonChecked>
<ComboBoxChecked>5</ComboBoxChecked>
</Root>
My goal is to add a Namespace to it.
How can i achieve this?
You can add namespaces at root level this way:
XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("example", "http://www.w3.org");
using (var ms = new MemoryStream())
{
using (TextWriter writer = new StreamWriter(ms))
{
var xmlSerializer = new XmlSerializer(typeof(MyClass));
xmlSerializer.Serialize(writer, myClassInstance, ns);
XNode node = XElement.Parse(Encoding.ASCII.GetString(ms.ToArray()));
}
}
If you need namespaces in it's children, you can edit your class using the IXmlSerializable interface, here's an Example
Related
I am trying to serialize a class in c# but the output is not quite I am after. I want to get rid of one element in output xml - class name - that comes along with serialization.
My class is:
[XmlType("ADSobjotsing")]
public class ObjKompParam
{
[XmlElement("aadressTekst")]
public string Tekst;
[XmlElement("adsOid")]
public string OID;
My code is:
protected override XElement ComposeQueryBody(object InputParams)
{
ObjKompParam param = (ObjKompParam)InputParams;
var ads_o_q = new ObjKompParam();
XElement body = new XElement(SOAPNS + "Body",
new XElement(prod + "ADSobjotsing"));
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
XmlSerializer serializer = new XmlSerializer(typeof(ObjKompParam),"");
XElement xe;
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, param, ns);
stream.Position = 0;
using (XmlReader reader = XmlReader.Create(stream))
{
xe = XElement.Load(reader);
}
}
body.Descendants(prod + "ADSobjotsing").First().Add(new XElement(xe));
return body;
}
The output I get is:
<SOAP-ENV:Body>
<prod:ADSobjotsing>
<ADSobjotsing>
<aadressTekst>Sügise 10</aadressTekst>
</ADSobjotsing>
</prod:ADSobjotsing>
</SOAP-ENV:Body>
The xml output (body) I am after is following:
<SOAP-ENV:Body>
<prod:ADSobjotsing>
<aadressTekst>Sügise 10</aadressTekst>
</prod:ADSobjotsing>
</SOAP-ENV:Body>
I answer myself, as I worked out the solution:
XmlSerializer serializer = new XmlSerializer(typeof(ObjKompParam),"");
XElement xe;
using (var stream = new MemoryStream()) //write into stream
{
serializer.Serialize(stream, param, ns); //writer, object
stream.Position = 0;
using (XmlReader reader = XmlReader.Create(stream))
{
xe = XElement.Load(reader);
}
}
var child = xe.Descendants();
body.Descendants(prod + "ADSobjotsing").First().Add(child);
return body;
I made the new variable for object class ObjKompParam children and added children as descendants.
I'm given a xsd generated C# POCO object that I need to convert to xml. The expected payload however doesn't match the xsds I was given. Specifically, I need to omit the declaration and remove all namespaces from the xml object so that the company in question accepts the API request.
Problem
Given an object of type T, I want to serialize it without declaration and namespace.
I've gotten rid of most of it but q1 has been added to each element for some reason. How do I remove that?
Attempt
After some research, I saw several posts provide a solution that creates an empty xml serializer namespace and calls serializer with that object. That only got me half way there.
Usage
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
var body = payload.SerializeObject(false, true, ns);
Extension Method
public static string SerializeObject<T>(this T obj, bool indented, bool omitDeclaration, XmlSerializerNamespaces ns)
{
var utf8NoBom = new UTF8Encoding(false);
var settings = new XmlWriterSettings
{
OmitXmlDeclaration = omitDeclaration,
Indent = indented,
Encoding = utf8NoBom
};
using (MemoryStream ms = new MemoryStream())
{
using (var xmlWriter = XmlWriter.Create(ms, settings))
{
XmlSerializer xmlSer = new XmlSerializer(typeof(T));
xmlSer.Serialize(xmlWriter, obj, ns);
byte[] bytes = ms.ToArray();
return utf8NoBom.GetString(bytes);
}
}
}
Unfortunately the results looks like this.
<q1:InventoryFeed xmlns:q1=\"http://thecompany.com/\">
<q1:InventoryHeader>
<q1:version>1.4</q1:version>
</q1:InventoryHeader>
<q1:inventory>
<q1:sku>WMSkuCap0180</q1:sku>
<q1:quantity>
<q1:unit>EACH</q1:unit>
<q1:amount>3</q1:amount>
</q1:quantity>
<q1:fulfillmentLagTime>1</q1:fulfillmentLagTime>
</q1:inventory>
</q1:InventoryFeed>
How do I remove the namespace completely?
The simplest way is to 'post-process' the XML:
var doc = XDocument.Parse(xml);
doc.Descendants().Attributes().Where(a => a.IsNamespaceDeclaration).Remove();
foreach (var element in doc.Descendants())
{
element.Name = element.Name.LocalName;
}
var xmlWithoutNamespaces = doc.ToString();
The other option (as you can't amend the source class XML attributes) is to implement a decorator for XmlWriter that ignores all namespaces, but it's quite a large class so there'd be a lot of boilerplate delegation.
This is another solution:
XmlWriterSettings settings = new XmlWriterSettings();
//If you wish Encoding
settings.Encoding = Encoding.GetEncoding("ISO-8859-1");
using (XmlWriter xmlWriter = XmlWriter.Create(tempFilePath, settings))
{
var ns = new XmlSerializerNamespaces();
ns.Add("", "http://thecompany.com");
XmlSerializer s = new XmlSerializer(YOUROBJECT.GetType(), "http://thecompany.com");
s.Serialize(xmlWriter, YOUROBJECT, ns);
}
I sometimes use RegEx or XML Linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string input =
"<q1:InventoryFeed xmlns:q1=\"http://thecompany.com/\">\n" +
"<q1:InventoryHeader>\n" +
"<q1:version>1.4</q1:version>\n" +
"</q1:InventoryHeader>\n" +
"<q1:inventory>v" +
"<q1:sku>WMSkuCap0180</q1:sku>\n" +
"<q1:quantity>\n" +
"<q1:unit>EACH</q1:unit>\n" +
"<q1:amount>3</q1:amount>\n" +
"</q1:quantity>\n" +
"<q1:fulfillmentLagTime>1</q1:fulfillmentLagTime>\n" +
"</q1:inventory>\n" +
"</q1:InventoryFeed>\n";
string pattern1 = #"<[^/][^:]+:";
string output = Regex.Replace(input, pattern1, "<");
string pattern2 = #"</[^:]+:";
output = Regex.Replace(output, pattern2, "</");
//using xml linq
XElement element = XElement.Parse(input);
foreach (var node in element.DescendantNodesAndSelf())
{
if (node.NodeType == XmlNodeType.Element)
{
((XElement)node).Name = ((XElement)node).Name.LocalName;
}
}
}
}
}
I want to add
xsi:noNamespaceSchemaLocation="FullModeDataset.xsd"
and
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
as attibutes to my root node "ApplicationData" so the root node will look like this..
<ApplicationData
xsi:noNamespaceSchemaLocation="FullModeDataset.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
I am creating the xml from a string, outputing a string that is proper xml with this code..
var doc = new XmlDocument();
doc.LoadXml(myInputXmlString);
var ms = new MemoryStream();
var tx = XmlWriter.Create(ms,
new XmlWriterSettings
{
OmitXmlDeclaration = false,
ConformanceLevel = ConformanceLevel.Document,
Encoding = UTF8Encoding.UTF8
});
doc.Save(tx);
//I TRIED THE COMMENTED CODE BELOW BUT WITH NO SUCCESS
//XmlAttribute newAttr = doc.CreateAttribute("xsi:noNamespaceSchemaLocation");
//newAttr.Value = "FullModeDataset.xsd";
//XmlElement applicationNode = doc.DocumentElement["AppicationData"];
//applicationNode.Attributes.Append(newAttr);
//doc.Save(tx);
var xmlString = UTF8Encoding.UTF8.GetString(ms.ToArray());
how do I add these attributes to my xml string?
You need to create the attribute using the overload which takes the prefix and the namespace URL of the attribute you want to create, as shown below:
public class StackOverflow_14128649
{
public static void Test()
{
string myInputXmlString = #"<ApplicationData>
<something>else</something>
</ApplicationData>";
var doc = new XmlDocument();
doc.LoadXml(myInputXmlString);
XmlAttribute newAttr = doc.CreateAttribute(
"xsi",
"noNamespaceSchemaLocation",
"http://www.w3.org/2001/XMLSchema-instance");
newAttr.Value = "FullModeDataset.xsd";
doc.DocumentElement.Attributes.Append(newAttr);
var ms = new MemoryStream();
XmlWriterSettings ws = new XmlWriterSettings
{
OmitXmlDeclaration = false,
ConformanceLevel = ConformanceLevel.Document,
Encoding = UTF8Encoding.UTF8
};
var tx = XmlWriter.Create(ms, ws);
doc.Save(tx);
tx.Flush();
var xmlString = UTF8Encoding.UTF8.GetString(ms.ToArray());
Console.WriteLine(xmlString);
}
}
I need to set the OmitXmlDeclaration property of the XmlWriterSettings for a XmlWriter to false to not have XML declarations created. The issue is that I have created the XmlWriter from a call of a XPathNavigator.AppendChild() method. Code below:
public String GetEntityXml<T>(List<T> entities)
{
XmlDocument xmlDoc = new XmlDocument();
XPathNavigator nav = xmlDoc.CreateNavigator();
using (XmlWriter writer = nav.AppendChild())
{
XmlSerializer ser = new XmlSerializer(typeof(List<T>), new XmlRootAttribute(typeof(T).Name + "_LIST"));
ser.Serialize(writer, entities);
}
StringWriter stringWriter = new StringWriter();
XmlTextWriter xmlTextWriter = new XmlTextWriter(stringWriter);
xmlDoc.WriteTo(xmlTextWriter);
string resultString = stringWriter.ToString();
stringWriter.Close();
xmlTextWriter.Close();
return resultString;
}
Any idea how to serialize the List and not have XML declarations?
I’m not getting the XML declaration when I execute your code. Serializing a List<int> gives me:
<Int32_LIST xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<int>5</int>
<int>7</int>
<int>2</int>
</Int32_LIST>
Note that the “XML declaration” that OmitXmlDeclaration refers to is typically something similar to:
<?xml version="1.0" encoding="UTF-8" ?>
If you’re instead referring to the xmlns parts, then those are called “XML namespace declarations”, and may be eliminated by initializing an XmlSerializerNamespaces instance with a default empty namespace, and passing it to your Serialize method:
XmlSerializer ser = new XmlSerializer(typeof(List<T>), new XmlRootAttribute(typeof(T).Name + "_LIST"));
var namespaces = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("", "") });
ser.Serialize(writer, entities, namespaces);
The below is a shortened implementation which achieves the same result as your code:
public String GetEntityXml<T>(List<T> entities)
{
var sb = new StringBuilder();
var settings = new XmlWriterSettings { OmitXmlDeclaration = true };
using (XmlWriter writer = XmlWriter.Create(sb, settings))
{
XmlSerializer ser = new XmlSerializer(typeof(List<T>), new XmlRootAttribute(typeof(T).Name + "_LIST"));
var namespaces = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("", "") });
ser.Serialize(writer, entities, namespaces);
}
return sb.ToString();
}
Try this approach (switched to var for readability):
public String GetEntityXml<T>(List<T> entities)
{
var xmlDoc = new XmlDocument();
var nav = xmlDoc.CreateNavigator();
using (var sw = new StringWriter())
{
//Create an XmlWriter that will omit xml declarations
var s = new XmlWriterSettings{ OmitXmlDeclaration = true };
using (var xmlWriter = XmlWriter.Create(sw, s))
{
//Use the following to serialize without namespaces
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
var ser = new XmlSerializer(typeof(List<T>),
new XmlRootAttribute(typeof(T).Name + "_LIST"));
ser.Serialize(xmlWriter, entities, ns);
}
//Pass xml string to nav.AppendChild()
nav.AppendChild(sw.ToString());
}
using (var stringWriter = new StringWriter())
{
using (var xmlTextWriter = XmlWriter.Create(stringWriter))
{
xmlDoc.WriteTo(xmlTextWriter);
}
return stringWriter.ToString();
}
}
Rather than using nav.AppendChild() to create the XmlWriter, you can create the XmlWriter separately and then just use nav.AppendChild(string) to write the XML into xmlDoc. When you create the XmlWriter yourself, you can omit the XML declaration. Also, when you serialize, you'll probably want to omit the xmlns:xsi and xmlns:xsd namespaces using the XmlSerializerNamespaces class.
What is the best way to convert the C# object to XmlEmenet?
Do I just use XmlSerializer and import the XmlNode or is there a better way?
This is what I found out there wondering if there is any other better way.
public XmlElement Serialize(XmlDocument document)
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
XmlElement returnVal;
XmlSerializer serializer = new XmlSerializer(this.GetType());
MemoryStream ms = new MemoryStream();
XmlTextWriter tw = new XmlTextWriter(ms, UTF8Encoding.UTF8);
XmlDocument doc = new XmlDocument();
tw.Formatting = Formatting.Indented;
tw.IndentChar = ' ';
serializer.Serialize(tw, this, ns);
ms.Seek(0, SeekOrigin.Begin);
doc.Load(ms);
returnVal = document.ImportNode(doc.DocumentElement, true) as XmlElement;
return returnVal;
}
You can make that into an Extension Method on the Object Type so you don't have to put that method in a bunch of different classes.