Search code examples
c#xmlxmltextwriter

Little help using XmlTextWriter on writing "xhtml:link" element of sitemap.xml


Hello I'm trying to write a string like :

 <xhtml:link rel="alternate" hreflang="de" href="http://www.example.com/de" />

using XmlTextWriter class

I've tried this piece of code:

// Write Alternative links _writer.WriteStartElement("xhtml:link"); _writer.WriteAttributeString("rel","alternate"); _writer.WriteAttributeString("hreflang", "de"); _writer.WriteAttributeString("href", "http://example.com/de"); _writer.WriteEndElement();

Which generates this error: Namespace prefix xhtml on link is not defined

But I don't need any namespaces provided for xhtml:link

Question: How to achieve the string that I need using XmlTextWriter?

Update 1: I have changed to LINQ to XML

But for now I have another problem... For the beginning I'll show the code:

    private readonly XNamespace nsXhtml = "http://www.w3.org/1999/xhtml";
    private readonly XNamespace nsSitemap = "http://www.sitemaps.org/schemas/sitemap/0.9";
    private readonly XNamespace nsXsi = "http://www.w3.org/2001/XMLSchema-instance";
    private readonly XNamespace nsLocation = "http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd";

    public XDocument Generate()
    {
        var sitemap = new XDocument(new XDeclaration("1.0", "utf-8", "yes"));

        var urlSet = new XElement(nsSitemap + "urlset",
            new XAttribute("xmlns", nsSitemap),
            new XAttribute(XNamespace.Xmlns + "xhtml", nsXhtml),
            new XAttribute(XNamespace.Xmlns + "xsi", nsXsi),
            new XAttribute(nsXsi + "schemaLocation", nsLocation),
            from node in GenerateUrlNodes() // Provides a collection of "objects", actually it doesn't matter since we anyway convert them to XElement below...
            select WriteUrlLocation(node.Url,node.UpdateFrequency,node.LastModified));

        sitemap.Add(urlSet);

        return sitemap;
    }

    protected XElement WriteUrlLocation(string url, UpdateFrequency updateFrequency, DateTime lastUpdated)
    {
        var urlNode = new XElement(nsSitemap + "url",
            new XElement(nsSitemap + "loc", url),
            new XElement(nsSitemap + "changefreq", updateFrequency),
            new XElement(nsSitemap + "lastmod", lastUpdated)
            );

        var linkNode = new XElement(nsXhtml + "link",
            new XAttribute("rel", "alternate"),
            new XAttribute("hreflang", "de"),
            new XAttribute("href", "http://example.com/de"));

        urlNode.Add(linkNode);
        return urlNode;
    }

The problem is that When I inspect the Generated sitemap at Controller:

    public ActionResult Sitemap()
    {
        var sitemap = _sitemapGenerator.Generate().ToString();
        return Content(sitemap,"text/xml");
    }

The whole xml is not as expected and, the <xhtml:link> element is rendered with a non-empty closing tag (thus I don't know if this is a problem here) .. Look at the image please

enter image description here

Update 2: Solved! Seems that the XML structure is valid but the browser is not displaying it right...


Solution

  • You should change to use a different overload of XmlWriter.StartElement. For example:

    _writer.WriteStartElement("link", "http://www.w3.org/1999/xhtml");
    

    That assumes you've already got a prefix alias of xhtml for the namespace http://www.w3.org/1999/xhtml. I'd still recommend shifting to use LINQ to XML as soon as you can though... XmlWriter is great for cases where you really need to stream the data (e.g. when it's huge) but otherwise, LINQ to XML makes things a lot easier:

    XNamespace xhtml = "http://www.w3.org/1999/xhtml";
    var element = new XElement(xhtml + "link",
         new XAttribute("rel", "alternate"),
         new XAttribute("hreflang", "de"),
         new XAttribute("href", "http://example.com/de"));
    parent.Add(element);