Skip to content

Instantly share code, notes, and snippets.

@xakpc
Created September 19, 2023 22:39
Show Gist options
  • Save xakpc/c4ab9c023ad031ed9a992c8ca8199212 to your computer and use it in GitHub Desktop.
Save xakpc/c4ab9c023ad031ed9a992c8ca8199212 to your computer and use it in GitHub Desktop.
Azure Function To Fix Hashnode Sitemap
using System;
using System.IO;
using System.Threading.Tasks;
using System.Web.Http;
using System.Xml.Serialization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System.Globalization;
using System.Xml.Linq;
namespace ApiChat.Functions.OneTimeFunctions;
public static class HashnodeSitemapFunction
{
[FunctionName("HashnodeSitemapFunction")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "sitemap-fix")] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HashnodeSitemapFunction processed a request.");
string url = req.Query["url"];
if (string.IsNullOrEmpty(url))
{
return new BadRequestErrorMessageResult("url parameter is required");
}
var client = new System.Net.Http.HttpClient();
var response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
// read response xml to string
var responseString = await response.Content.ReadAsStringAsync();
// deserialize and rebuild
var sitemapNodes = new List<SitemapNode>();
try
{
var serializer = new XmlSerializer(typeof(UrlSet));
var sitemap = (UrlSet)serializer.Deserialize(new StringReader(responseString));
foreach (var urlSetUrl in sitemap.Urls)
{
if (!Enum.TryParse<SitemapFrequency>(urlSetUrl.ChangeFreq, true, out var frequency))
{
frequency = SitemapFrequency.Never;
}
sitemapNodes.Add(new SitemapNode()
{
Url = urlSetUrl.Loc,
Frequency = frequency,
LastModified = urlSetUrl.LastMod,
Priority = (double?)urlSetUrl.Priority
});
}
}
catch (Exception e)
{
log.LogError(e, "Failed to parse sitemap");
return new BadRequestErrorMessageResult($"Failed to parse sitemap with error: {e.Message}");
}
return new ContentResult
{
Content = GetSitemapDocument(sitemapNodes),
ContentType = "application/xml",
StatusCode = 200
};
}
[XmlRoot("urlset", Namespace = "http://www.sitemaps.org/schemas/sitemap/0.9")]
public class UrlSet
{
[XmlElement("url")]
public List<Url> Urls { get; set; }
}
public class Url
{
[XmlElement("loc")]
public string Loc { get; set; }
[XmlElement("changefreq")]
public string? ChangeFreq { get; set; }
[XmlElement("priority")]
public decimal? Priority { get; set; }
[XmlElement("lastmod")]
public DateTime? LastMod { get; set; }
}
internal class SitemapNode
{
public SitemapFrequency? Frequency { get; set; }
public DateTime? LastModified { get; set; }
public double? Priority { get; set; }
public string Url { get; set; }
}
internal enum SitemapFrequency
{
Never,
Yearly,
Monthly,
Weekly,
Daily,
Hourly,
Always
}
/// <summary>
/// Serializes to raw XML.
/// </summary>
private static string GetSitemapDocument(IEnumerable<SitemapNode> sitemapNodes)
{
XNamespace xmlns = "http://www.sitemaps.org/schemas/sitemap/0.9";
var root = new XElement(xmlns + "urlset");
foreach (var sitemapNode in sitemapNodes)
{
var urlElement = new XElement(
xmlns + "url",
new XElement(xmlns + "loc", Uri.EscapeUriString(sitemapNode.Url)),
sitemapNode.Frequency == null
? null
: new XElement(
xmlns + "changefreq",
sitemapNode.Frequency.Value.ToString().ToLowerInvariant()),
sitemapNode.Priority == null
? null
: new XElement(
xmlns + "priority",
sitemapNode.Priority.Value.ToString("F1", CultureInfo.InvariantCulture)),
sitemapNode.LastModified == null
? null
: new XElement(
xmlns + "lastmod",
sitemapNode.LastModified.Value.ToLocalTime().ToString("yyyy-MM-ddTHH:mm:sszzz")));
root.Add(urlElement);
}
var document = new XDocument(root);
return document.ToString();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment