Dynamic XML depending on List properties

I’m trying to create and XML Sitemap, and I’m tasked to create it using a List and in a way that if the ImageName property in the List in empty, the XML ignores it but if the property is not empty, it will use the property to build the XML block correctly.

This is what I’m currently using to build the XML:

string imageURL = "https://images.ontheedgebrands.com/images/";

XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
XNamespace gs = "http://www.sitemaps.org/schemas/sitemap/0.9";
XNamespace nsImage = "http://www.google.com/schemas/sitemap-image/1.1";

XDocument doc = new XDocument(
    new XElement(gs + "urlset",
    new XAttribute("xmlns", gs),
    new XAttribute(XNamespace.Xmlns + "image", nsImage),
    new XAttribute(XNamespace.Xmlns + "xsi", xsi),
    new XAttribute(xsi + "schemaLocation", "http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"),

    from rw in rwlist select
    new XElement(gs + "url",
    new XElement(gs + "loc", site + rw.SEOURL),
    new XElement(nsImage + "image",
        new XElement(nsImage + "loc", imageURL + rw.ImageName)),
    new XElement(gs + "changefreq", "weekly"),
    new XElement(gs + "priority", rw.Priority)
)));

doc.Save(file);

And depending on if the rw.ImageName property in in the list and not empty, I want it to build the XML dynamically and look something like this:

<url>
    <loc>https://www.budk.com/$10-$20-3231</loc>
    <changefreq>weekly</changefreq>
    <priority>1.0</priority>
</url>
<url>
    <loc>https://www.budk.com/$20-$50-3232</loc>
    <changefreq>weekly</changefreq>
    <priority>1.0</priority>
</url>
<url>
    <loc>https://www.budk.com/-308-Black-Lower-Receiver-Kit--80-Percent-36485</loc>
    <image:image>
        <image:loc>https://images.ontheedgebrands.com/images/A52-PO2331.jpg</image:loc>
    </image:image>
    <changefreq>weekly</changefreq>
    <priority>1.0</priority>
</url>
<url>
    <loc>https://www.budk.com/-40-Cal-Blowgun-Broadhead-Dart-25-Per-Pack-20739</loc>
    <image:image>
        <image:loc>https://images.ontheedgebrands.com/images/A08-SFBGBHD25.jpg</image:loc>
    </image:image>
    <changefreq>weekly</changefreq>
    <priority>1.0</priority>
</url>

The first two objects in the list had the ImageName property empty and the third and fourth list object had an ImageName so they where build differently.

With the code, right now the XML looks like this, and I don’t want the first two XML blocks to add an image attribute because the ImageName property in the List is empty:

<url>
    <loc>https://www.budk.com/$10-$20-3231</loc>
    <image:image>
        <image:loc>https://images.ontheedgebrands.com/images/</image:loc>
    </image:image>
    <changefreq>weekly</changefreq>
    <priority>1.0</priority>
</url>
<url>
    <loc>https://www.budk.com/$20-$50-3232</loc>
    <image:image>
        <image:loc>https://images.ontheedgebrands.com/images/</image:loc>
    </image:image>
    <changefreq>weekly</changefreq>
    <priority>1.0</priority>
</url>
<url>
    <loc>https://www.budk.com/-308-Black-Lower-Receiver-Kit--80-Percent-36485</loc>
    <image:image>
        <image:loc>https://images.ontheedgebrands.com/images/A52-PO2331.jpg</image:loc>
    </image:image>
    <changefreq>weekly</changefreq>
    <priority>1.0</priority>
</url>
<url>
    <loc>https://www.budk.com/-40-Cal-Blowgun-Broadhead-Dart-25-Per-Pack-20739</loc>
    <image:image>
        <image:loc>https://images.ontheedgebrands.com/images/A08-SFBGBHD25.jpg</image:loc>
    </image:image>
    <changefreq>weekly</changefreq>
    <priority>1.0</priority>
</url>

Answer

You can use the fact that LINQ to XML ignores null values when adding them. So all you need to do is change this code that unconditionally creates the image element:

new XElement(nsImage + "image",
    new XElement(nsImage + "loc", imageURL + rw.ImageName)),

… to this:

string.IsNullOrEmpty(rw.ImageName)
   ? null
   : new XElement(nsImage + "image", new XElement(nsImage + "loc", imageURL + rw.ImageName)),

You could also potentially simplify the code a bit by setting up those XName values beforehand:

XNamespace nsImage = "http://www.google.com/schemas/sitemap-image/1.1";
XName imageXName = nsImage + "image";
XName imageLocXName = nsImage + "loc";

...

// In the argument list
string.IsNullOrEmpty(rw.ImageName)
   ? null
   : new XElement(imageXName, new XElement(imageLocXName, imageURL + rw.ImageName)),