This new solution works better (looks like is even faster), but I was looking for a simple solution to skip empty nodes. We didn't want <node></node> or <node />.
So in the end I tried something like this:
using System;
using System.Linq;
using System.Xml.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var b3 = string.Empty; // "3"
XDocument x = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("a",
new XElement("b1", "1"),
ElemString("b2", "2"),
ElemString("b3", b3),
new XElement("b4", string.Empty),
new XElement("b5", null),
ElemChildren("c", ElemString("c1", "11"), ElemString("c2", string.Empty)),
ElemChildren("d", ElemString("d1", string.Empty), ElemString("d2", string.Empty))
)
);
x.Save(Console.Out);
Console.ReadKey();
}
static XElement ElemChildren(string name, params object[] children) {
return children.Where( obj => obj != null).Any() ? new XElement(name, children) : null;
}
static XElement ElemString(string name, string val) {
return string.IsNullOrEmpty(val) ? null : new XElement(name, val);
}
}
}
which produces:
<?xml version="1.0" encoding="utf-8"?>
<a>
<b1>1</b1>
<b2>2</b2>
<b4></b4>
<b5 />
<c>
<c1>11</c1>
</c>
</a>
ElemChildren() was used to exclude a node having all children Null, while ElemString() is a simple ternary function (here's only for strings, most important part).
Notice the difference between <b4></b4> and <b5 />. Also notice that node <d> is missing completely because of all Null children nodes.
Notice the difference between <b4></b4> and <b5 />. Also notice that node <d> is missing completely because of all Null children nodes.