Brantley Blanchard
Brantley Blanchard

Reputation: 1218

Remove q1 and all namespaces from xml

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

Answers (4)

Maxence
Maxence

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

Gonzalo Bustamante
Gonzalo Bustamante

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

Charles Mager
Charles Mager

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

jdweng
jdweng

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

Related Questions