How to add xml prefix using XDocument?

1.7k views Asked by At

How do I add xml prefixes using XDocument to an existing root element? I have the following XML:

<processSalesOrder>
  <header/>
</processSalesOrder>

and I want it to look like:

<ns0:processSalesOrder xmlns:ns0='https://xyx/'>
  <header/>
</ns0:processSalesOrder>

In my scenario, I am receiving this xml from web api and passing it long to another web service. The web service is expecting a namespace prefix on the root element.

The web service is from a third party software, it is expecting the xml in a certain format. I tried XmlDocument, XDocument etc ... I couldn't find a way to add the namespace prefix only on the root element. Webservice was rejecting the transactions if the prefix was on Descendants.

3

There are 3 answers

2
Hitesh Anshani On

Got Reference from here Developer Name: Vijay Sirigiri

If you are trying to add namespace to the elements after loading the xml document then it is not possible.

From MSDN:

You cannot add, modify, or delete an XML namespace definition in an instance of an XML document after the document has been loaded into the XML Document Object Model (XMLDOM) parser. The XML nodes that are used to represent data in the XML document are created when the document is loaded into the XMLDOM parser. These nodes are permanently bound to their XML namespace attributes when they are created. Therefore, the empty XML namespace declaration (xmlns = "") is appended to the child nodes of these nodes to preserve the default XML namespace attribute of these nodes.

However you can load the input, read each element and write it to another document (or in-memory) which has the namespace set. Below is the code that parses the string xml, creates a new xml element along with namespace prefix and namespace.

            String xmlWithoutNamespace =
                @"<Folio><Node1>Value1</Node1><Node2>Value2</Node2><Node3>Value3</Node3></Folio>";
            String prefix ="vs";
            String testNamespace = "http://www.testnamespace/vs/";
            XmlDocument xmlDocument = new XmlDocument();

            XElement folio = XElement.Parse(xmlWithoutNamespace);
            XmlElement folioNode = xmlDocument.CreateElement(prefix, folio.Name.LocalName, testNamespace);

            var nodes = from node in folio.Elements()
                        select node;

            foreach (XElement item in nodes)
            {
                var node = xmlDocument.CreateElement(prefix, item.Name.ToString(), testNamespace);
                node.InnerText = item.Value;
                folioNode.AppendChild(node);
            }

            xmlDocument.AppendChild(folioNode);

xmlDocument now contains the xml with each node prefixed with vs.

6
Marc Gravell On

You're trying to specify an alias for the empty namespace. XDocument doesn't allow that:

The prefix 'ns0' cannot be bound to the empty namespace name.

So no, I don't think you can do this with XDocument. I don't think it is even valid XML to do so - emphasis mine:

[Definition:] If the attribute name matches PrefixedAttName, then the NCName gives the namespace prefix, used to associate element and attribute names with the namespace name in the attribute value in the scope of the element to which the declaration is attached. In such declarations, the namespace name may not be empty.

[Definition:] If the attribute name matches DefaultAttName, then the namespace name in the attribute value is that of the default namespace in the scope of the element to which the declaration is attached. In such a default declaration, the attribute value may be empty. Default namespaces and overriding of declarations are discussed in "5. Applying Namespaces to Elements and Attributes".

0
Dijkgraaf On

As per Roberts comment, you can add the namespace in the Receive Pipeline using a add namespace pipeline component. If you have BizTalk Enterprise and have installed the ESB Toolkit there is an out of the box one called ESB Add Namespace, or you have to write your own Pipeline Component to do this.

The other option is to have two schemas, one without the namespace that you specify in your XML dissasembler component in your Receive Pipeline, another schema with the namespace and you have a map from one to the other. This second schema should have ElementFormDefault set to (Default) or Unqualified if you don't want the namespace prefixes on the Elements. If you are future proofing it, you would also have a canonical/internal schema and map from the source schema to the internal schema on the Receive Port and from the internal to the destination schema on the Send Port.