mirror of https://github.com/Jackett/Jackett
Redid xml to json conversion
This commit is contained in:
parent
4eaacaeb94
commit
8d3dfd43d4
|
@ -1,4 +1,4 @@
|
|||
using Newtonsoft.Json.Serialization;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace Jackett.Common.Helpers
|
||||
{
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Jackett.Common.Extensions;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Jackett.Common.Helpers
|
||||
{
|
||||
public static class XmlToJsonConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts an XML element to a JSON object.
|
||||
/// Attributes are stored in an @attributes object.
|
||||
/// </summary>
|
||||
public static JToken XmlToJson(XElement element)
|
||||
{
|
||||
var obj = new JObject();
|
||||
|
||||
// Build @attributes object from element attributes
|
||||
if (element.Attributes().Any())
|
||||
{
|
||||
var attributes = element.Attributes()
|
||||
.ToDictionary(
|
||||
attribute => GetName(attribute.Name, attribute.Parent?.Document),
|
||||
attribute => (JToken)attribute.Value
|
||||
);
|
||||
obj.Add("@attributes", JObject.FromObject(attributes));
|
||||
}
|
||||
|
||||
foreach (var childElement in element.Elements())
|
||||
{
|
||||
var childObj = XmlToJson(childElement);
|
||||
var childName = GetName(childElement.Name, element.Document);
|
||||
|
||||
// If the child name already exists, convert it to an array
|
||||
if (obj.ContainsKey(childName))
|
||||
{
|
||||
if (obj[childName] is JArray existingArray)
|
||||
{
|
||||
existingArray.Add(childObj);
|
||||
}
|
||||
else
|
||||
{
|
||||
obj[childName] = new JArray(obj[childName]!, childObj);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
obj.Add(childName, childObj);
|
||||
}
|
||||
}
|
||||
|
||||
if (!element.Elements().Any() && !element.Value.IsNullOrWhiteSpace())
|
||||
{
|
||||
return element.Value;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static string GetName(XName name, XDocument document)
|
||||
{
|
||||
if (document == null)
|
||||
{
|
||||
return name.LocalName;
|
||||
}
|
||||
|
||||
var prefix = document.Root?.GetPrefixOfNamespace(name.Namespace);
|
||||
return prefix != null ? $"{prefix}:{name.LocalName}" : name.LocalName;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Jackett.Common.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// JsonTextWriter to convert XML to JSON.
|
||||
/// Makes sure that XML attributes do not have the '@' or '#' prefix in the JSON output.
|
||||
/// https://stackoverflow.com/a/43485727
|
||||
/// </summary>
|
||||
public class XmlToJsonWriter : JsonTextWriter
|
||||
{
|
||||
public XmlToJsonWriter(TextWriter textWriter) : base(textWriter)
|
||||
{
|
||||
}
|
||||
|
||||
public override void WritePropertyName(string name)
|
||||
{
|
||||
if (name.StartsWith("@") || name.StartsWith("#"))
|
||||
{
|
||||
base.WritePropertyName(name.Substring(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
base.WritePropertyName(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,8 @@ using System.Linq;
|
|||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Xml.Linq;
|
||||
using Jackett.Common.Helpers;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Jackett.Common.Models
|
||||
{
|
||||
|
@ -52,7 +54,7 @@ namespace Jackett.Common.Models
|
|||
return new XElement(_TorznabNs + "attr", new XAttribute("name", name), new XAttribute("value", value));
|
||||
}
|
||||
|
||||
public string ToXml(Uri selfAtom)
|
||||
private XDocument GetXDocument(Uri selfAtom)
|
||||
{
|
||||
// IMPORTANT: We can't use Uri.ToString(), because it generates URLs without URL encode (links with unicode
|
||||
// characters are broken). We must use Uri.AbsoluteUri instead that handles encoding correctly
|
||||
|
@ -127,7 +129,19 @@ namespace Jackett.Common.Models
|
|||
)
|
||||
);
|
||||
|
||||
return xdoc;
|
||||
}
|
||||
|
||||
public string ToXml(Uri selfAtom)
|
||||
{
|
||||
var xdoc = GetXDocument(selfAtom);
|
||||
return xdoc.Declaration + Environment.NewLine + xdoc;
|
||||
}
|
||||
|
||||
public string ToJson(Uri selfAtom, JsonSerializerSettings serializerSettings = null)
|
||||
{
|
||||
var jsonObject = XmlToJsonConverter.XmlToJson(GetXDocument(selfAtom).Root);
|
||||
return JsonConvert.SerializeObject(jsonObject, serializerSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
using Jackett.Common.Helpers;
|
||||
using Newtonsoft.Json;
|
||||
|
@ -358,15 +356,8 @@ namespace Jackett.Common.Models
|
|||
|
||||
public string ToJson(JsonSerializerSettings serializerSettings = null)
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
var serializer = JsonSerializer.Create(serializerSettings);
|
||||
|
||||
using var stringWriter = new StringWriter(stringBuilder);
|
||||
using var jsonWriter = new XmlToJsonWriter(stringWriter);
|
||||
|
||||
serializer.Serialize(jsonWriter, GetXDocument().Root);
|
||||
|
||||
return stringBuilder.ToString();
|
||||
var jsonObject = XmlToJsonConverter.XmlToJson(GetXDocument().Root);
|
||||
return JsonConvert.SerializeObject(jsonObject, serializerSettings);
|
||||
}
|
||||
|
||||
public static TorznabCapabilities Concat(TorznabCapabilities lhs, TorznabCapabilities rhs)
|
||||
|
|
|
@ -359,7 +359,7 @@ namespace Jackett.Server.Controllers
|
|||
if (string.Equals(CurrentQuery.QueryType, "caps", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return CurrentQuery.IsJson ?
|
||||
(IActionResult)Json(CurrentIndexer.TorznabCaps.ToJson(_JsonSerializerSettings)) :
|
||||
Content(CurrentIndexer.TorznabCaps.ToJson(_JsonSerializerSettings), "application/json", Encoding.UTF8) :
|
||||
Content(CurrentIndexer.TorznabCaps.ToXml(), "application/rss+xml", Encoding.UTF8);
|
||||
}
|
||||
|
||||
|
@ -378,24 +378,6 @@ namespace Jackett.Server.Controllers
|
|||
else if (string.Equals(request.configured, "false", StringComparison.InvariantCultureIgnoreCase))
|
||||
indexers = indexers.Where(i => !i.IsConfigured);
|
||||
|
||||
if (CurrentQuery.IsJson)
|
||||
{
|
||||
return Json(new JObject
|
||||
{
|
||||
["indexers"] = JArray.FromObject(indexers.Select(i => new
|
||||
{
|
||||
id = i.Id,
|
||||
configured = i.IsConfigured,
|
||||
title = i.Name,
|
||||
description = i.Description,
|
||||
link = i.SiteLink,
|
||||
language = i.Language,
|
||||
type = i.Type,
|
||||
caps = i.TorznabCaps
|
||||
}))
|
||||
});
|
||||
}
|
||||
|
||||
var xdoc = new XDocument(
|
||||
new XDeclaration("1.0", "UTF-8", null),
|
||||
new XElement("indexers",
|
||||
|
@ -413,6 +395,11 @@ namespace Jackett.Server.Controllers
|
|||
)
|
||||
);
|
||||
|
||||
if (CurrentQuery.IsJson)
|
||||
{
|
||||
return Json(XmlToJsonConverter.XmlToJson(xdoc.Root), _JsonSerializerSettings);
|
||||
}
|
||||
|
||||
return Content(xdoc.Declaration.ToString() + Environment.NewLine + xdoc.ToString(), "application/xml", Encoding.UTF8);
|
||||
}
|
||||
|
||||
|
@ -502,12 +489,14 @@ namespace Jackett.Server.Controllers
|
|||
else
|
||||
logger.Info($"Torznab search in {CurrentIndexer.Name} for {CurrentQuery.GetQueryString()} => Found {result.Releases.Count()} releases{cacheStr} [{stopwatch.ElapsedMilliseconds:0}ms]");
|
||||
|
||||
var serverUri = new Uri(serverUrl);
|
||||
if (CurrentQuery.IsJson)
|
||||
{
|
||||
return Json(resultPage);
|
||||
var json = resultPage.ToJson(serverUri);
|
||||
return Content(json, "application/json", Encoding.UTF8);
|
||||
}
|
||||
|
||||
var xml = resultPage.ToXml(new Uri(serverUrl));
|
||||
var xml = resultPage.ToXml(serverUri);
|
||||
|
||||
// Force the return as XML
|
||||
return Content(xml, "application/rss+xml", Encoding.UTF8);
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
using System.Xml.Linq;
|
||||
using Jackett.Common.Helpers;
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Jackett.Test.Common.Helpers
|
||||
{
|
||||
[TestFixture]
|
||||
public class XmlToJsonConverterTests
|
||||
{
|
||||
[Test]
|
||||
public void XmlToJsonConverter_XmlToJson_Empty()
|
||||
{
|
||||
var element = new XElement("test");
|
||||
var json = XmlToJsonConverter.XmlToJson(element);
|
||||
Assert.AreEqual("{}", json.ToString(Formatting.None));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void XmlToJsonConverter_XmlToJson_WithAttributes()
|
||||
{
|
||||
var element = new XElement("test", new XAttribute("attr1", "value1"), new XAttribute("attr2", "value2"));
|
||||
var json = XmlToJsonConverter.XmlToJson(element);
|
||||
Assert.AreEqual("{\"@attributes\":{\"attr1\":\"value1\",\"attr2\":\"value2\"}}", json.ToString(Formatting.None));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void XmlToJsonConverter_XmlToJson_WithChildElement()
|
||||
{
|
||||
var element = new XElement("test", new XElement("child"));
|
||||
var json = XmlToJsonConverter.XmlToJson(element);
|
||||
Assert.AreEqual("{\"child\":{}}", json.ToString(Formatting.None));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void XmlToJsonConverter_XmlToJson_WithChildElement_WithAttributes()
|
||||
{
|
||||
var element = new XElement("test", new XElement("child", new XAttribute("attr1", "value1"), new XAttribute("attr2", "value2")));
|
||||
var json = XmlToJsonConverter.XmlToJson(element);
|
||||
Assert.AreEqual("{\"child\":{\"@attributes\":{\"attr1\":\"value1\",\"attr2\":\"value2\"}}}", json.ToString(Formatting.None));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void XmlToJsonConverter_XmlToJson_WithChildElement_WithText()
|
||||
{
|
||||
var element = new XElement("test", new XElement("child", new XElement("subchild", "text")));
|
||||
var json = XmlToJsonConverter.XmlToJson(element);
|
||||
Assert.AreEqual("{\"child\":{\"subchild\":\"text\"}}", json.ToString(Formatting.None));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void XmlToJsonConverter_XmlToJson_WithChildElementArray()
|
||||
{
|
||||
var element = new XElement("test", new XElement("child"), new XElement("child"));
|
||||
var json = XmlToJsonConverter.XmlToJson(element);
|
||||
Assert.AreEqual("{\"child\":[{},{}]}", json.ToString(Formatting.None));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void XmlToJsonConverter_XmlToJson_WithChildElementArray_WithText()
|
||||
{
|
||||
var element = new XElement("test", new XElement("child", "text1"), new XElement("child", "text2"));
|
||||
var json = XmlToJsonConverter.XmlToJson(element);
|
||||
Assert.AreEqual("{\"child\":[\"text1\",\"text2\"]}", json.ToString(Formatting.None));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void XmlToJsonConverter_XmlToJson_HandlesNamespaces()
|
||||
{
|
||||
var document = new XDocument(
|
||||
new XElement("root",
|
||||
new XAttribute(XNamespace.Xmlns + "ns1", "http://example.com/ns1"),
|
||||
new XAttribute(XNamespace.Xmlns + "ns2", "http://example.com/ns2"),
|
||||
new XElement("{http://example.com/ns1}child1"),
|
||||
new XElement("{http://example.com/ns2}child2")
|
||||
)
|
||||
);
|
||||
|
||||
var json = XmlToJsonConverter.XmlToJson(document.Root);
|
||||
Assert.AreEqual("{\"@attributes\":{\"xmlns:ns1\":\"http://example.com/ns1\",\"xmlns:ns2\":\"http://example.com/ns2\"},\"ns1:child1\":{},\"ns2:child2\":{}}", json.ToString(Formatting.None));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue