Search code examples
c#xmlxmlwriter

Custom indent for default xmlns attribute wile writing through XmlWriter


I'm struggling a bit trying to find the appropriate way of writing exactly this XML with XmlWriter and underlying string builder:

<x:node xmlns="uri:default"
        xmlns:x="uri:special-x"
        xmlns:y="uri:special-y"
        y:name="MyNode"
        SomeOtherAttr="ok">
</x:node>

The best I have so far:

static string GetXml()
{
    var r = new StringBuilder();
    var w = XmlWriter.Create(r, new XmlWriterSettings { OmitXmlDeclaration = true });
    w.WriteStartElement("x", "node", "uri:special-x");
    w.Flush();
    r.Append("\n" + new string(' ', 7));
    w.WriteAttributeString("xmlns", "x", null, "uri:special-x");
    w.Flush();
    r.Append("\n" + new string(' ', 7));
    w.WriteAttributeString("xmlns", "y", null, "uri:special-y");
    w.Flush();
    r.Append("\n" + new string(' ', 7));
    w.WriteAttributeString("name", "uri:special-y", "vd");
    w.Flush();
    r.Append("\n" + new string(' ', 7));
    w.WriteAttributeString("SomeOtherAttr", "ok");
    w.Flush();
    w.WriteEndElement();
    w.Flush();
    return r.ToString();
}

which creates

<x:node
        xmlns:x="uri:special-x"
        xmlns:y="uri:special-y"
        y:name="vd"
        SomeOtherAttr="ok" />

but I cannot find a way to write default xmlns right after the node. Any try leads to error or different formatting.

Any ideas? Thanks!

Update: maybe I can write it directly to the StringBuilder but I look for more... hm.. correct approach.


Solution

  • You'd need to actually add your default namespace, which you're currently not doing:

    var sb = new StringBuilder();
    var writer = XmlWriter.Create(sb, new XmlWriterSettings
    {
        OmitXmlDeclaration = true,
    });
    
    using (writer)
    {
        writer.WriteStartElement("x", "node", "uri:special-x");
        writer.WriteAttributeString("xmlns", "uri:default");
        writer.Flush();
        sb.Append("\n" + new string(' ', 7));
        writer.WriteAttributeString("xmlns", "x", null, "uri:special-x");
        writer.Flush();
        sb.Append("\n" + new string(' ', 7));
        writer.WriteAttributeString("xmlns", "y", null, "uri:special-y");
        writer.Flush();
        sb.Append("\n" + new string(' ', 7));
        writer.WriteAttributeString("name", "uri:special-y", "vd");
        writer.Flush();
        sb.Append("\n" + new string(' ', 7));
        writer.WriteAttributeString("SomeOtherAttr", "ok");            
        writer.WriteEndElement();
    }  
    

    See this demo: https://dotnetfiddle.net/994YqW

    That being said, why are you trying to do this? Just let it format it how it likes, it's still semantically the same and perfectly valid.