Reputation: 1218
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?
Upvotes: 8
Views: 11400
Reputation: 13329
This works for me :
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
class Program
{
static void Main(string[] args)
{
var serializer = new XmlSerializer(typeof(Person), "");
var namespaces = new XmlSerializerNamespaces();
namespaces.Add("", "");
using (var stream = new MemoryStream())
{
var someone = new Person
{
FirstName = "Isaac",
LastName = "Newton"
};
serializer.Serialize(stream, someone, namespaces);
var utf8NoBom = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
byte[] bytes = stream.ToArray();
Console.WriteLine(utf8NoBom.GetString(bytes));
}
}
}
You need to pass an empty string as the default namespace in the XmlSerializer
constructor.
Upvotes: 0
Reputation: 401
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);
}
Upvotes: 7
Reputation: 26223
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.
Upvotes: 10
Reputation: 34421
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;
}
}
}
}
}
Upvotes: -3