0

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.

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

I need to compare many WPF files and want to convert them to the "canonical" form to simplify it and potentially use the result as auto-formatting tool for the project files. For this the documents should be formatted in the way VS/Resharper does it + some "canonical" rules like ordered attributes etc.
That makes some sense. Normally XML isn't for human consumption, but XAML is a bit of a special case!
1

Why so hard? Try this please:

var r = new StringBuilder();

var settings = new XmlWriterSettings
{
    OmitXmlDeclaration = true,
    NewLineOnAttributes = true,
    Indent = true,
    IndentChars = "\t"
};

using (var w = XmlWriter.Create(r, settings))
{
    w.WriteStartElement("x", "node", "uri:special-x");

    w.WriteAttributeString("xmlns", "x", null, "uri:special-x");
    w.WriteAttributeString("xmlns", "y", null, "uri:special-y");
    w.WriteAttributeString("name", "uri:special-y", "vd");
    w.WriteAttributeString("SomeOtherAttr", "ok");

    w.WriteEndElement();
}

All namespaces will be on one line.

2 Comments

Thanks, nice one. Is there anything like NewLineOnAttributes but for namespaces as well?
@AlexAtNet Unfortunately no.

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.