0

I need to create an XML document with C# that is like this:

<?xml version="1.0" encoding="utf-8"?>
<Container>
  <Info>
    <request xmlns:a="http://www.UKMail.com/Services/Contracts/DataContracts">
      <a:AuthenticationToken>token</a:AuthenticationToken>
      <a:Username>username</a:Username>
      <a:ConsignmentNumber>12345</a:ConsignmentNumber>
    </request>
  </Info>
</Container>

The critical part is the namespace definition with a prefix (xmlns:a=...) is in a child node, not the root node. I have only been able to produce this document so far:

<?xml version="1.0" encoding="utf-8"?>
<Container xmlns:a="http://www.UKMail.com/Services/Contracts/DataContracts">
  <Info>
    <a:request>
      <a:AuthenticationToken>token</a:AuthenticationToken>
      <a:Username>username</a:Username>
      <a:ConsignmentNumber>12345</a:ConsignmentNumber>
    </a:request>
  </Info>
</Container>

This is rejected by the web service - if you move the xmlns:a.. part to the request node the web service is happy with it.

This is how I am generating the XML at the moment:

class Program
    {
        static void Main(string[] args)
        {
            SerializeObject("XmlNamespaces.xml");
        }

        public static void SerializeObject(string filename)
        {
            var mySerializer = new XmlSerializer(typeof(Container));
            // Writing a file requires a TextWriter.
            TextWriter myWriter = new StreamWriter(filename);

            // Creates an XmlSerializerNamespaces and adds two
            // prefix-namespace pairs.
            var myNamespaces = new XmlSerializerNamespaces();
            myNamespaces.Add("a", "http://www.UKMail.com/Services/Contracts/DataContracts");


            Container container = new Container
            {
                Info = new CancelConsignmentRequest
                {
                    request = new CancelConsignmentRequestInfo
                    {
                        AuthenticationToken = "token",
                        ConsignmentNumber = "12345",
                        Username = "username"
                    }
                }
            };

            mySerializer.Serialize(myWriter, container, myNamespaces);
            myWriter.Close();
        }
    }

    public class Container
    {
        public CancelConsignmentRequest Info { get; set; } = new CancelConsignmentRequest();
    }

    [XmlRoot(Namespace = "http://www.UKMail.com/Services/Contracts/ServiceContracts")]
    public class CancelConsignmentRequest
    {
        [XmlElement(Namespace = "http://www.UKMail.com/Services/Contracts/DataContracts")]
        public CancelConsignmentRequestInfo request { get; set; } = new CancelConsignmentRequestInfo();
    }

    public class CancelConsignmentRequestInfo
    {
        [XmlElement(Namespace = "http://www.UKMail.com/Services/Contracts/DataContracts", Order = 0)]
        public string AuthenticationToken { get; set; }
        [XmlElement(Namespace = "http://www.UKMail.com/Services/Contracts/DataContracts", Order = 1)]
        public string Username { get; set; }

        [XmlElement(Namespace = "http://www.UKMail.com/Services/Contracts/DataContracts", Order = 2)]
        public string ConsignmentNumber { get; set; }
    }

I have not been able to work out how to place the namespace definition with a prefix in one of the child nodes. Does anyone know how to do this in C# please? Thanks.

8
  • "The critical part is ... This is rejected by the web service" - shouldn't it be a bug report to a service author instead? Commented Sep 22, 2020 at 10:16
  • @Sinatr the XML is still valid isn't it? Therefore you should be able to produce it with C#. Commented Sep 22, 2020 at 10:18
  • Second XML is also valid. Why service is not supporting xml standard? Commented Sep 22, 2020 at 10:25
  • One weird approach would be to serialize xml without namespaces, then read it back with XmlDocument and set namespace with SetAttribute overload accepting URI. Commented Sep 22, 2020 at 10:29
  • 2
    Does this answer your question? XML namespace on child element Commented Sep 22, 2020 at 11:14

1 Answer 1

3

This is possible. The code below does what you are asking for.

class Program
{
    static void Main(string[] args)
    {
        SerializeObject("XmlNamespaces.xml");
    }

    public static void SerializeObject(string filename)
    {
        var mySerializer = new XmlSerializer(typeof(Container));
        // Writing a file requires a TextWriter.
        TextWriter myWriter = new StreamWriter(filename);

        // Creates an XmlSerializerNamespaces and adds two
        // prefix-namespace pairs.
        var myNamespaces = new XmlSerializerNamespaces();
        //myNamespaces.Add("a", "http://www.UKMail.com/Services/Contracts/DataContracts");

        Container container = new Container
        {
            Info = new CancelConsignmentRequest
            {
                request = new CancelConsignmentRequestInfo
                {
                    AuthenticationToken = "token",
                    ConsignmentNumber = "12345",
                    Username = "username"
                }
            }
        };

        mySerializer.Serialize(myWriter, container, myNamespaces);
        myWriter.Close();
    }
}

public class Container
{
    public CancelConsignmentRequest Info { get; set; } = new CancelConsignmentRequest();
}

public class CancelConsignmentRequest
{
    public CancelConsignmentRequestInfo request { get; set; } = new CancelConsignmentRequestInfo();
}

[XmlRoot(Namespace = "http://www.UKMail.com/Services/Contracts/ServiceContracts")]
public class CancelConsignmentRequestInfo
{
    [XmlNamespaceDeclarations]
    public XmlSerializerNamespaces xmlns = new XmlSerializerNamespaces(
        new[] { new XmlQualifiedName("a", "http://www.UKMail.com/Services/Contracts/DataContracts"), });
    [XmlElement(Namespace = "http://www.UKMail.com/Services/Contracts/DataContracts", Order = 0)]
    public string AuthenticationToken { get; set; }
    [XmlElement(Namespace = "http://www.UKMail.com/Services/Contracts/DataContracts", Order = 1)]
    public string Username { get; set; }

    [XmlElement(Namespace = "http://www.UKMail.com/Services/Contracts/DataContracts", Order = 2)]
    public string ConsignmentNumber { get; set; }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks - it still leaves the a: at the start of the request node, which the web service doesn't like. I've edited your reply to remove an annotation which then gives me the desired output.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.