From a3a9ab069a227a1502caf790ec554fe322e63767 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Tue, 19 Feb 2013 22:09:55 +0600 Subject: [PATCH 1/3] Applying patch for #U4-1636 --- src/Umbraco.Core/Dynamics/DynamicXml.cs | 205 ++++++++++-------- src/Umbraco.Core/PublishedContentHelper.cs | 2 +- src/Umbraco.Core/XmlHelper.cs | 54 +++++ .../DynamicXmlConverterTests.cs | 62 ++++++ .../PublishedContent/DynamicXmlTests.cs | 91 +++----- src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + 6 files changed, 269 insertions(+), 146 deletions(-) create mode 100644 src/Umbraco.Tests/PublishedContent/DynamicXmlConverterTests.cs diff --git a/src/Umbraco.Core/Dynamics/DynamicXml.cs b/src/Umbraco.Core/Dynamics/DynamicXml.cs index f0942d02a8..a099099970 100644 --- a/src/Umbraco.Core/Dynamics/DynamicXml.cs +++ b/src/Umbraco.Core/Dynamics/DynamicXml.cs @@ -16,6 +16,23 @@ namespace Umbraco.Core.Dynamics public class DynamicXml : DynamicObject, IEnumerable, IEnumerable { public XElement BaseElement { get; set; } + private XElement _cleanedBaseElement; + + /// + /// Returns a cleaned Xml element which is purely used for matching against names for elements and attributes + /// when the normal names don't match, for example when the original names contain hyphens. + /// + /// + private XElement GetCleanedBaseElement() + { + if (_cleanedBaseElement == null) + { + if (BaseElement == null) + throw new InvalidOperationException("Cannot return a cleaned XML element when the BaseElement is null"); + _cleanedBaseElement = XElement.Parse(XmlHelper.StripDashesInElementOrAttributeNames(BaseElement.ToString())); + } + return _cleanedBaseElement; + } public DynamicXml(XElement baseElement) { @@ -128,50 +145,112 @@ namespace Umbraco.Core.Dynamics result = null; return false; } - //Go ahead and try to fetch all of the elements matching the member name, and wrap them - var elements = BaseElement.Elements(binder.Name); - if (!elements.Any() && BaseElement.Name == "root" && BaseElement.Elements().Count() == 1) - { - //no elements matched, lets try first child - elements = BaseElement.Elements().ElementAt(0).Elements(binder.Name); - } - if (HandleIEnumerableXElement(elements, out result)) - { - return true; - } - else - { - //Ok, so no elements matched, so lets try attributes - IEnumerable attributes = BaseElement.Attributes(binder.Name).Select(attr => attr.Value); - int count = attributes.Count(); - - if (count > 0) + //First check for matching name including the 'cleaned' name (i.e. removal of hyphens, etc... ) + var elementByNameAttempt = CheckNodeNameMatch(binder.Name, BaseElement, true); + if (elementByNameAttempt.Success) + { + if (HandleIEnumerableXElement(elementByNameAttempt.Result, out result)) { - if (count > 1) - result = attributes; //more than one attribute matched, lets return the collection - else - result = attributes.FirstOrDefault(); //only one attribute matched, lets just return it - - return true; // return true because we matched + return true; + } + } + + //Ok, so no elements matched, so lets try attributes + var attributeByNameAttempt = CheckAttributeNameMatch(binder.Name, BaseElement, true); + if (attributeByNameAttempt.Success) + { + if (attributeByNameAttempt.Result.Count() > 1) + { + //more than one attribute matched, lets return the collection + result = attributeByNameAttempt.Result; } else { - //no attributes matched, lets try first child - if (BaseElement.Name == "root" && BaseElement.Elements().Count() == 1) - { - attributes = BaseElement.Elements().ElementAt(0).Attributes(binder.Name).Select(attr => attr.Value); - count = attributes.Count(); - if (count > 1) - result = attributes; //more than one attribute matched, lets return the collection - else - result = attributes.FirstOrDefault(); //only one attribute matched, lets just return it + //only one attribute matched, lets just return it + result = attributeByNameAttempt.Result.FirstOrDefault(); + } + return true; + } + - return true; // return true because we matched - } + return base.TryGetMember(binder, out result); + } + + private Attempt> CheckAttributeNameMatch(string name, XElement xmlElement, bool checkCleanedName) + { + var attributes = xmlElement.Attributes(name).Select(attr => attr.Value).ToArray(); + if (attributes.Any()) + { + return new Attempt>(true, attributes); + } + + //NOTE: this seems strange we're checking for the term 'root', this is legacy code so we'll keep it i guess + if (!attributes.Any() && xmlElement.Name == "root" && xmlElement.Elements().Count() == 1) + { + //no elements matched and this node is called 'root' and only has one child... lets see if it matches. + var childElements = xmlElement.Elements().ElementAt(0).Attributes(name).Select(attr => attr.Value).ToArray(); + if (childElements.Any()) + { + //we've found a match by the first child of an element called 'root' (strange, but sure) + return new Attempt>(true, childElements); } } - return base.TryGetMember(binder, out result); + + if (checkCleanedName) + { + //still no match, we'll try to match with a 'cleaned' name + var cleanedXml = GetCleanedBaseElement(); + + //pass false in to this as we don't want an infinite loop and clean the already cleaned xml + return CheckAttributeNameMatch(name, cleanedXml, false); + } + + //no deal + return Attempt>.False; + } + + /// + /// Checks if the 'name' matches any elements of xmlElement + /// + /// The name to match + /// The xml element to check against + /// If there are no matches, we'll clean the xml (i.e. remove hyphens, etc..) and then retry + /// + private Attempt> CheckNodeNameMatch(string name, XElement xmlElement, bool checkCleanedName) + { + //Go ahead and try to fetch all of the elements matching the member name, and wrap them + var elements = xmlElement.Elements(name).ToArray(); + + //Check if we've got any matches, if so then return true + if (elements.Any()) + { + return new Attempt>(true, elements); + } + + //NOTE: this seems strange we're checking for the term 'root', this is legacy code so we'll keep it i guess + if (!elements.Any() && xmlElement.Name == "root" && xmlElement.Elements().Count() == 1) + { + //no elements matched and this node is called 'root' and only has one child... lets see if it matches. + var childElements = xmlElement.Elements().ElementAt(0).Elements(name).ToArray(); + if (childElements.Any()) + { + //we've found a match by the first child of an element called 'root' (strange, but sure) + return new Attempt>(true, childElements); + } + } + + if (checkCleanedName) + { + //still no match, we'll try to match with a 'cleaned' name + var cleanedXml = GetCleanedBaseElement(); + + //pass false in to this as we don't want an infinite loop and clean the already cleaned xml + return CheckNodeNameMatch(name, cleanedXml, false); + } + + //no deal + return Attempt>.False; } private bool HandleIEnumerableXElement(IEnumerable elements, out object result) @@ -193,7 +272,7 @@ namespace Umbraco.Core.Dynamics //We have more than one matching element, so let's return the collection //elements is IEnumerable //but we want to be able to re-enter this code - XElement root = new XElement(XName.Get("root")); + var root = new XElement(XName.Get("root")); root.Add(elements); result = new DynamicXml(root); @@ -205,6 +284,7 @@ namespace Umbraco.Core.Dynamics result = null; return false; } + public DynamicXml XPath(string expression) { var matched = this.BaseElement.XPathSelectElements(expression); @@ -689,57 +769,10 @@ namespace Umbraco.Core.Dynamics return test(this) ? new HtmlString(valueIfTrue) : new HtmlString(valueIfFalse); } + [Obsolete("Use XmlHelper.StripDashesInElementOrAttributeNames instead")] public static string StripDashesInElementOrAttributeNames(string xml) { - using (MemoryStream outputms = new MemoryStream()) - { - using (TextWriter outputtw = new StreamWriter(outputms)) - { - using (MemoryStream ms = new MemoryStream()) - { - using (TextWriter tw = new StreamWriter(ms)) - { - tw.Write(xml); - tw.Flush(); - ms.Position = 0; - using (TextReader tr = new StreamReader(ms)) - { - bool IsInsideElement = false, IsInsideQuotes = false; - int ic = 0; - while ((ic = tr.Read()) != -1) - { - if (ic == (int)'<' && !IsInsideQuotes) - { - if (tr.Peek() != (int)'!') - { - IsInsideElement = true; - } - } - if (ic == (int)'>' && !IsInsideQuotes) - { - IsInsideElement = false; - } - if (ic == (int)'"') - { - IsInsideQuotes = !IsInsideQuotes; - } - if (!IsInsideElement || ic != (int)'-' || IsInsideQuotes) - { - outputtw.Write((char)ic); - } - } - - } - } - } - outputtw.Flush(); - outputms.Position = 0; - using (TextReader outputtr = new StreamReader(outputms)) - { - return outputtr.ReadToEnd(); - } - } - } + return XmlHelper.StripDashesInElementOrAttributeNames(xml); } diff --git a/src/Umbraco.Core/PublishedContentHelper.cs b/src/Umbraco.Core/PublishedContentHelper.cs index 94fc293e4c..d0710fa872 100644 --- a/src/Umbraco.Core/PublishedContentHelper.cs +++ b/src/Umbraco.Core/PublishedContentHelper.cs @@ -78,7 +78,7 @@ namespace Umbraco.Core { try { - var e = XElement.Parse(DynamicXml.StripDashesInElementOrAttributeNames(sResult), LoadOptions.None); + var e = XElement.Parse(sResult, LoadOptions.None); //check that the document element is not one of the disallowed elements //allows RTE to still return as html if it's valid xhtml diff --git a/src/Umbraco.Core/XmlHelper.cs b/src/Umbraco.Core/XmlHelper.cs index 27f4d0e923..3e67f2728e 100644 --- a/src/Umbraco.Core/XmlHelper.cs +++ b/src/Umbraco.Core/XmlHelper.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Xml; @@ -14,6 +15,59 @@ namespace Umbraco.Core public class XmlHelper { + public static string StripDashesInElementOrAttributeNames(string xml) + { + using (var outputms = new MemoryStream()) + { + using (TextWriter outputtw = new StreamWriter(outputms)) + { + using (var ms = new MemoryStream()) + { + using (var tw = new StreamWriter(ms)) + { + tw.Write(xml); + tw.Flush(); + ms.Position = 0; + using (var tr = new StreamReader(ms)) + { + bool IsInsideElement = false, IsInsideQuotes = false; + int ic = 0; + while ((ic = tr.Read()) != -1) + { + if (ic == (int)'<' && !IsInsideQuotes) + { + if (tr.Peek() != (int)'!') + { + IsInsideElement = true; + } + } + if (ic == (int)'>' && !IsInsideQuotes) + { + IsInsideElement = false; + } + if (ic == (int)'"') + { + IsInsideQuotes = !IsInsideQuotes; + } + if (!IsInsideElement || ic != (int)'-' || IsInsideQuotes) + { + outputtw.Write((char)ic); + } + } + + } + } + } + outputtw.Flush(); + outputms.Position = 0; + using (TextReader outputtr = new StreamReader(outputms)) + { + return outputtr.ReadToEnd(); + } + } + } + } + /// /// Imports a XML node from text. /// diff --git a/src/Umbraco.Tests/PublishedContent/DynamicXmlConverterTests.cs b/src/Umbraco.Tests/PublishedContent/DynamicXmlConverterTests.cs new file mode 100644 index 0000000000..dad9649564 --- /dev/null +++ b/src/Umbraco.Tests/PublishedContent/DynamicXmlConverterTests.cs @@ -0,0 +1,62 @@ +using System.Xml; +using System.Xml.Linq; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Dynamics; +using Umbraco.Tests.PartialTrust; + +namespace Umbraco.Tests.PublishedContent +{ + [TestFixture] + public class DynamicXmlConverterTests : AbstractPartialTrustFixture + { + [Test] + public void Convert_To_String() + { + var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; + var dXml = new DynamicXml(xml); + var result = dXml.TryConvertTo(); + Assert.IsTrue(result.Success); + Assert.AreEqual(xml, result.Result); + } + + [Test] + public void Convert_To_XElement() + { + var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; + var dXml = new DynamicXml(xml); + var result = dXml.TryConvertTo(); + Assert.IsTrue(result.Success); + Assert.AreEqual(xml, result.Result.ToString(SaveOptions.DisableFormatting)); + } + + [Test] + public void Convert_To_XmlElement() + { + var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; + var dXml = new DynamicXml(xml); + var result = dXml.TryConvertTo(); + Assert.IsTrue(result.Success); + Assert.AreEqual(xml, result.Result.OuterXml); + } + + [Test] + public void Convert_To_XmlDocument() + { + var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; + var dXml = new DynamicXml(xml); + var result = dXml.TryConvertTo(); + Assert.IsTrue(result.Success); + Assert.AreEqual(xml, result.Result.InnerXml); + } + + public override void TestSetup() + { + + } + + public override void TestTearDown() + { + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/PublishedContent/DynamicXmlTests.cs b/src/Umbraco.Tests/PublishedContent/DynamicXmlTests.cs index 4fc304730a..a566ce5cee 100644 --- a/src/Umbraco.Tests/PublishedContent/DynamicXmlTests.cs +++ b/src/Umbraco.Tests/PublishedContent/DynamicXmlTests.cs @@ -1,74 +1,47 @@ using System; using System.Diagnostics; -using System.Xml; -using System.Xml.Linq; using Microsoft.CSharp.RuntimeBinder; using NUnit.Framework; using Umbraco.Core.Dynamics; using System.Linq; -using Umbraco.Tests.PartialTrust; -using Umbraco.Core; namespace Umbraco.Tests.PublishedContent { - [TestFixture] - public class DynamicXmlConverterTests : AbstractPartialTrustFixture - { - [Test] - public void Convert_To_String() - { - var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; - var dXml = new DynamicXml(xml); - var result = dXml.TryConvertTo(); - Assert.IsTrue(result.Success); - Assert.AreEqual(xml, result.Result); - } - - [Test] - public void Convert_To_XElement() - { - var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; - var dXml = new DynamicXml(xml); - var result = dXml.TryConvertTo(); - Assert.IsTrue(result.Success); - Assert.AreEqual(xml, result.Result.ToString(SaveOptions.DisableFormatting)); - } - - [Test] - public void Convert_To_XmlElement() - { - var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; - var dXml = new DynamicXml(xml); - var result = dXml.TryConvertTo(); - Assert.IsTrue(result.Success); - Assert.AreEqual(xml, result.Result.OuterXml); - } - - [Test] - public void Convert_To_XmlDocument() - { - var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; - var dXml = new DynamicXml(xml); - var result = dXml.TryConvertTo(); - Assert.IsTrue(result.Success); - Assert.AreEqual(xml, result.Result.InnerXml); - } - - public override void TestSetup() - { - - } - - public override void TestTearDown() - { - } - } - - [TestFixture] + [TestFixture] public class DynamicXmlTests { + /// + /// Ensures that when we return the xml structure we get the real structure, not the replaced hyphen structure + /// see: http://issues.umbraco.org/issue/U4-1405#comment=67-5113 + /// http://issues.umbraco.org/issue/U4-1636 + /// + [Test] + public void Deals_With_Hyphenated_values() + { + var xml = @" + + True + 1161 + /content/ + 12 december Zorgbeurs Care + +"; - [Test] + var typedXml = new DynamicXml(xml); + dynamic dynamicXml = typedXml; + + var typedElement = typedXml.BaseElement.Element("url-picker"); + var dynamicElementByCleanedName = dynamicXml.urlpicker; + + Assert.IsNotNull(typedElement); + Assert.IsNotNull(dynamicElementByCleanedName); + + Assert.AreEqual( + typedElement.Attribute("some-attribute").Value, + dynamicElementByCleanedName.someattribute); + } + + [Test] public void Custom_Extension_Method_Legacy() { var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 0824305bd9..0aabfe93b2 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -187,6 +187,7 @@ + From 8d38cf3c4471e61643fa0b18bd747066da435fbb Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Tue, 19 Feb 2013 22:11:55 +0600 Subject: [PATCH 2/3] Applying patch for #U4-1636 --- src/Umbraco.Core/Dynamics/DynamicXml.cs | 253 +++++++++++------- .../Dynamics/DynamicXmlConverter.cs | 95 ++++++- .../DynamicXmlConverterTests.cs | 52 +++- .../PublishedContent/DynamicXmlTests.cs | 8 +- .../RazorDynamicNode/LegacyConverter.cs | 2 +- 5 files changed, 300 insertions(+), 110 deletions(-) diff --git a/src/Umbraco.Core/Dynamics/DynamicXml.cs b/src/Umbraco.Core/Dynamics/DynamicXml.cs index a099099970..103128a3b6 100644 --- a/src/Umbraco.Core/Dynamics/DynamicXml.cs +++ b/src/Umbraco.Core/Dynamics/DynamicXml.cs @@ -9,70 +9,120 @@ using System.Xml.XPath; using System.Collections; using System.IO; using System.Web; +using Umbraco.Core; namespace Umbraco.Core.Dynamics { [TypeConverter(typeof(DynamicXmlConverter))] public class DynamicXml : DynamicObject, IEnumerable, IEnumerable { - public XElement BaseElement { get; set; } - private XElement _cleanedBaseElement; + [Obsolete("Use StrippedXmlElement or RawXmlElement instead")] + public XElement BaseElement + { + get { return StrippedXmlElement; } + //This should have been read only but we're stuck with it now and we'll have to assume that a person is setting the 'raw' xml + set + { + Mandate.ParameterNotNull(value, "value"); + + RawXmlElement = value; + StrippedXmlElement = XElement.Parse( + XmlHelper.StripDashesInElementOrAttributeNames( + RawXmlElement.ToString())); + } + } + + /// + /// Returns the XElement used to create the DynamicXml structure + /// + public XElement RawXmlElement { get; internal set; } /// - /// Returns a cleaned Xml element which is purely used for matching against names for elements and attributes - /// when the normal names don't match, for example when the original names contain hyphens. + /// Returns the XElement for this DynamicXml structure that has been stripped of all of it's hyphens /// - /// - private XElement GetCleanedBaseElement() - { - if (_cleanedBaseElement == null) - { - if (BaseElement == null) - throw new InvalidOperationException("Cannot return a cleaned XML element when the BaseElement is null"); - _cleanedBaseElement = XElement.Parse(XmlHelper.StripDashesInElementOrAttributeNames(BaseElement.ToString())); - } - return _cleanedBaseElement; - } + public XElement StrippedXmlElement { get; private set; } public DynamicXml(XElement baseElement) { - this.BaseElement = baseElement; + if (baseElement == null) return; + + RawXmlElement = baseElement; + StrippedXmlElement = XElement.Parse( + XmlHelper.StripDashesInElementOrAttributeNames( + RawXmlElement.ToString())); } - public DynamicXml(string xml) + + internal DynamicXml(XElement rawXml, XElement strippedXml) { + if (rawXml == null) throw new ArgumentNullException("rawXml"); + if (strippedXml == null) throw new ArgumentNullException("strippedXml"); + + RawXmlElement = rawXml; + StrippedXmlElement = strippedXml; + } + + public DynamicXml(string xml) + { + if (xml.IsNullOrWhiteSpace()) return; + var baseElement = XElement.Parse(xml); - this.BaseElement = baseElement; + RawXmlElement = baseElement; + StrippedXmlElement = XElement.Parse( + XmlHelper.StripDashesInElementOrAttributeNames( + xml)); } public DynamicXml(XPathNodeIterator xpni) { - if (xpni != null) - { - if (xpni.Current != null) - { - var xml = xpni.Current.OuterXml; - var baseElement = XElement.Parse(xml); - this.BaseElement = baseElement; - } - } + if (xpni == null) return; + if (xpni.Current == null) return; + + //TODO: OuterXml is really bad for performance! Should actually use the XPathNodeIterator api + var xml = xpni.Current.OuterXml; + var baseElement = XElement.Parse(xml); + RawXmlElement = baseElement; + StrippedXmlElement = XElement.Parse( + XmlHelper.StripDashesInElementOrAttributeNames( + xml)); } + + /// + /// Returns the InnertText based on the stripped xml element + /// public string InnerText { get { - return BaseElement.Value; + return StrippedXmlElement.Value; } } + + /// + /// Returns the string representation of the dash-stripped xml element + /// + /// public string ToXml() { - return BaseElement.ToString(SaveOptions.DisableFormatting); + return StrippedXmlElement.ToString(SaveOptions.DisableFormatting); } + + /// + /// Returns the string representation of the raw (no dash stripping) xml element + /// + /// + public string ToRawXml() + { + return RawXmlElement.ToString(SaveOptions.DisableFormatting); + } + public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) { int index = 0; if (indexes.Length > 0) { index = (int)indexes[0]; - result = new DynamicXml(this.BaseElement.Elements().ToList()[index]); + result = new DynamicXml( + RawXmlElement.Elements().ElementAt(index), + StrippedXmlElement.Elements().ElementAt(index)); return true; } return base.TryGetIndex(binder, indexes, out result); @@ -81,12 +131,12 @@ namespace Umbraco.Core.Dynamics { if (args.Length == 0 && binder.Name == "ToXml") { - result = this.BaseElement.ToString(); + result = StrippedXmlElement.ToString(); return true; } if (args.Length == 1 && binder.Name == "XPath") { - var elements = this.BaseElement.XPathSelectElements(args[0].ToString()); + var elements = StrippedXmlElement.XPathSelectElements(args[0].ToString()); HandleIEnumerableXElement(elements, out result); return true; //anyway } @@ -119,7 +169,9 @@ namespace Umbraco.Core.Dynamics } else if (attempt.Result.ObjectResult is IEnumerable) { - result = ((IEnumerable)attempt.Result.ObjectResult).Select(x => new DynamicXml(x.BaseElement)); + result = ((IEnumerable) attempt.Result.ObjectResult).Select(x => new DynamicXml( + x.RawXmlElement, + x.StrippedXmlElement)); } } } @@ -140,14 +192,14 @@ namespace Umbraco.Core.Dynamics } public override bool TryGetMember(GetMemberBinder binder, out object result) { - if (BaseElement == null || binder == null) + if (RawXmlElement == null || binder == null) { result = null; return false; } //First check for matching name including the 'cleaned' name (i.e. removal of hyphens, etc... ) - var elementByNameAttempt = CheckNodeNameMatch(binder.Name, BaseElement, true); + var elementByNameAttempt = CheckNodeNameMatch(binder.Name, RawXmlElement, true); if (elementByNameAttempt.Success) { if (HandleIEnumerableXElement(elementByNameAttempt.Result, out result)) @@ -157,7 +209,7 @@ namespace Umbraco.Core.Dynamics } //Ok, so no elements matched, so lets try attributes - var attributeByNameAttempt = CheckAttributeNameMatch(binder.Name, BaseElement, true); + var attributeByNameAttempt = CheckAttributeNameMatch(binder.Name, RawXmlElement, true); if (attributeByNameAttempt.Success) { if (attributeByNameAttempt.Result.Count() > 1) @@ -185,7 +237,6 @@ namespace Umbraco.Core.Dynamics return new Attempt>(true, attributes); } - //NOTE: this seems strange we're checking for the term 'root', this is legacy code so we'll keep it i guess if (!attributes.Any() && xmlElement.Name == "root" && xmlElement.Elements().Count() == 1) { //no elements matched and this node is called 'root' and only has one child... lets see if it matches. @@ -200,7 +251,7 @@ namespace Umbraco.Core.Dynamics if (checkCleanedName) { //still no match, we'll try to match with a 'cleaned' name - var cleanedXml = GetCleanedBaseElement(); + var cleanedXml = StrippedXmlElement; //pass false in to this as we don't want an infinite loop and clean the already cleaned xml return CheckAttributeNameMatch(name, cleanedXml, false); @@ -228,7 +279,6 @@ namespace Umbraco.Core.Dynamics return new Attempt>(true, elements); } - //NOTE: this seems strange we're checking for the term 'root', this is legacy code so we'll keep it i guess if (!elements.Any() && xmlElement.Name == "root" && xmlElement.Elements().Count() == 1) { //no elements matched and this node is called 'root' and only has one child... lets see if it matches. @@ -243,7 +293,7 @@ namespace Umbraco.Core.Dynamics if (checkCleanedName) { //still no match, we'll try to match with a 'cleaned' name - var cleanedXml = GetCleanedBaseElement(); + var cleanedXml = StrippedXmlElement; //pass false in to this as we don't want an infinite loop and clean the already cleaned xml return CheckNodeNameMatch(name, cleanedXml, false); @@ -285,19 +335,24 @@ namespace Umbraco.Core.Dynamics return false; } + /// + /// Executes an XPath expression over the dash-stripped Xml + /// + /// + /// public DynamicXml XPath(string expression) { - var matched = this.BaseElement.XPathSelectElements(expression); - DynamicXml root = new DynamicXml(""); + var matched = StrippedXmlElement.XPathSelectElements(expression); + var root = new DynamicXml(""); foreach (var element in matched) { - root.BaseElement.Add(element); + root.StrippedXmlElement.Add(element); } return root; } /// - /// Return the string version of Xml + /// Return the string version of the dash-stripped Xml /// /// public override string ToString() @@ -311,23 +366,23 @@ namespace Umbraco.Core.Dynamics } public DynamicXml Find(string expression) { - return new DynamicXml(this.BaseElement.XPathSelectElements(expression).FirstOrDefault()); + return new DynamicXml(StrippedXmlElement.XPathSelectElements(expression).FirstOrDefault()); } public DynamicXml Find(string attributeName, object value) { string expression = string.Format("//*[{0}='{1}']", attributeName, value); - return new DynamicXml(this.BaseElement.XPathSelectElements(expression).FirstOrDefault()); + return new DynamicXml(StrippedXmlElement.XPathSelectElements(expression).FirstOrDefault()); } IEnumerator IEnumerable.GetEnumerator() { - return this.BaseElement.Elements().GetEnumerator(); + return StrippedXmlElement.Elements().GetEnumerator(); } public IEnumerator GetEnumerator() { - return this.BaseElement.Elements().Select(e => new DynamicXml(e)).GetEnumerator(); + return StrippedXmlElement.Elements().Select(e => new DynamicXml(e)).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() @@ -390,7 +445,7 @@ namespace Umbraco.Core.Dynamics } public bool IsPosition(int index) { - if (this.BaseElement == null || this.BaseElement.Parent == null) + if (StrippedXmlElement == null || StrippedXmlElement.Parent == null) { return false; } @@ -398,7 +453,7 @@ namespace Umbraco.Core.Dynamics } public HtmlString IsPosition(int index, string valueIfTrue) { - if (this.BaseElement == null || this.BaseElement.Parent == null) + if (StrippedXmlElement == null || StrippedXmlElement.Parent == null) { return new HtmlString(string.Empty); } @@ -406,7 +461,7 @@ namespace Umbraco.Core.Dynamics } public HtmlString IsPosition(int index, string valueIfTrue, string valueIfFalse) { - if (this.BaseElement == null || this.BaseElement.Parent == null) + if (StrippedXmlElement == null || StrippedXmlElement.Parent == null) { return new HtmlString(valueIfFalse); } @@ -414,7 +469,7 @@ namespace Umbraco.Core.Dynamics } public bool IsModZero(int modulus) { - if (this.BaseElement == null || this.BaseElement.Parent == null) + if (StrippedXmlElement == null || StrippedXmlElement.Parent == null) { return false; } @@ -422,7 +477,7 @@ namespace Umbraco.Core.Dynamics } public HtmlString IsModZero(int modulus, string valueIfTrue) { - if (this.BaseElement == null || this.BaseElement.Parent == null) + if (StrippedXmlElement == null || StrippedXmlElement.Parent == null) { return new HtmlString(string.Empty); } @@ -430,7 +485,7 @@ namespace Umbraco.Core.Dynamics } public HtmlString IsModZero(int modulus, string valueIfTrue, string valueIfFalse) { - if (this.BaseElement == null || this.BaseElement.Parent == null) + if (StrippedXmlElement == null || StrippedXmlElement.Parent == null) { return new HtmlString(valueIfFalse); } @@ -439,7 +494,7 @@ namespace Umbraco.Core.Dynamics public bool IsNotModZero(int modulus) { - if (this.BaseElement == null || this.BaseElement.Parent == null) + if (StrippedXmlElement == null || StrippedXmlElement.Parent == null) { return false; } @@ -447,7 +502,7 @@ namespace Umbraco.Core.Dynamics } public HtmlString IsNotModZero(int modulus, string valueIfTrue) { - if (this.BaseElement == null || this.BaseElement.Parent == null) + if (StrippedXmlElement == null || this.StrippedXmlElement.Parent == null) { return new HtmlString(string.Empty); } @@ -455,7 +510,7 @@ namespace Umbraco.Core.Dynamics } public HtmlString IsNotModZero(int modulus, string valueIfTrue, string valueIfFalse) { - if (this.BaseElement == null || this.BaseElement.Parent == null) + if (this.StrippedXmlElement == null || this.StrippedXmlElement.Parent == null) { return new HtmlString(valueIfFalse); } @@ -463,7 +518,7 @@ namespace Umbraco.Core.Dynamics } public bool IsNotPosition(int index) { - if (this.BaseElement == null || this.BaseElement.Parent == null) + if (this.StrippedXmlElement == null || this.StrippedXmlElement.Parent == null) { return false; } @@ -471,7 +526,7 @@ namespace Umbraco.Core.Dynamics } public HtmlString IsNotPosition(int index, string valueIfTrue) { - if (this.BaseElement == null || this.BaseElement.Parent == null) + if (this.StrippedXmlElement == null || this.StrippedXmlElement.Parent == null) { return new HtmlString(string.Empty); } @@ -479,7 +534,7 @@ namespace Umbraco.Core.Dynamics } public HtmlString IsNotPosition(int index, string valueIfTrue, string valueIfFalse) { - if (this.BaseElement == null || this.BaseElement.Parent == null) + if (this.StrippedXmlElement == null || this.StrippedXmlElement.Parent == null) { return new HtmlString(valueIfFalse); } @@ -487,56 +542,56 @@ namespace Umbraco.Core.Dynamics } public bool IsLast() { - if (this.BaseElement == null || this.BaseElement.Parent == null) + if (this.StrippedXmlElement == null || this.StrippedXmlElement.Parent == null) { return false; } - int count = this.BaseElement.Parent.Elements().Count(); + int count = this.StrippedXmlElement.Parent.Elements().Count(); return IsHelper(n => n.Index() == count - 1); } public HtmlString IsLast(string valueIfTrue) { - if (this.BaseElement == null || this.BaseElement.Parent == null) + if (this.StrippedXmlElement == null || this.StrippedXmlElement.Parent == null) { return new HtmlString(string.Empty); } - int count = this.BaseElement.Parent.Elements().Count(); + int count = this.StrippedXmlElement.Parent.Elements().Count(); return IsHelper(n => n.Index() == count - 1, valueIfTrue); } public HtmlString IsLast(string valueIfTrue, string valueIfFalse) { - if (this.BaseElement == null || this.BaseElement.Parent == null) + if (this.StrippedXmlElement == null || this.StrippedXmlElement.Parent == null) { return new HtmlString(valueIfFalse); } - int count = this.BaseElement.Parent.Elements().Count(); + int count = this.StrippedXmlElement.Parent.Elements().Count(); return IsHelper(n => n.Index() == count - 1, valueIfTrue, valueIfFalse); } public bool IsNotLast() { - if (this.BaseElement == null || this.BaseElement.Parent == null) + if (this.StrippedXmlElement == null || this.StrippedXmlElement.Parent == null) { return false; } - int count = this.BaseElement.Parent.Elements().Count(); + int count = this.StrippedXmlElement.Parent.Elements().Count(); return !IsHelper(n => n.Index() == count - 1); } public HtmlString IsNotLast(string valueIfTrue) { - if (this.BaseElement == null || this.BaseElement.Parent == null) + if (this.StrippedXmlElement == null || this.StrippedXmlElement.Parent == null) { return new HtmlString(string.Empty); } - int count = this.BaseElement.Parent.Elements().Count(); + int count = this.StrippedXmlElement.Parent.Elements().Count(); return IsHelper(n => n.Index() != count - 1, valueIfTrue); } public HtmlString IsNotLast(string valueIfTrue, string valueIfFalse) { - if (this.BaseElement == null || this.BaseElement.Parent == null) + if (this.StrippedXmlElement == null || this.StrippedXmlElement.Parent == null) { return new HtmlString(valueIfFalse); } - int count = this.BaseElement.Parent.Elements().Count(); + int count = this.StrippedXmlElement.Parent.Elements().Count(); return IsHelper(n => n.Index() != count - 1, valueIfTrue, valueIfFalse); } public bool IsEven() @@ -565,87 +620,87 @@ namespace Umbraco.Core.Dynamics } public bool IsEqual(DynamicXml other) { - return IsHelper(n => n.BaseElement == other.BaseElement); + return IsHelper(n => n.StrippedXmlElement == other.StrippedXmlElement); } public HtmlString IsEqual(DynamicXml other, string valueIfTrue) { - return IsHelper(n => n.BaseElement == other.BaseElement, valueIfTrue); + return IsHelper(n => n.StrippedXmlElement == other.StrippedXmlElement, valueIfTrue); } public HtmlString IsEqual(DynamicXml other, string valueIfTrue, string valueIfFalse) { - return IsHelper(n => n.BaseElement == other.BaseElement, valueIfTrue, valueIfFalse); + return IsHelper(n => n.StrippedXmlElement == other.StrippedXmlElement, valueIfTrue, valueIfFalse); } public bool IsNotEqual(DynamicXml other) { - return IsHelper(n => n.BaseElement != other.BaseElement); + return IsHelper(n => n.StrippedXmlElement != other.StrippedXmlElement); } public HtmlString IsNotEqual(DynamicXml other, string valueIfTrue) { - return IsHelper(n => n.BaseElement != other.BaseElement, valueIfTrue); + return IsHelper(n => n.StrippedXmlElement != other.StrippedXmlElement, valueIfTrue); } public HtmlString IsNotEqual(DynamicXml other, string valueIfTrue, string valueIfFalse) { - return IsHelper(n => n.BaseElement != other.BaseElement, valueIfTrue, valueIfFalse); + return IsHelper(n => n.StrippedXmlElement != other.StrippedXmlElement, valueIfTrue, valueIfFalse); } public bool IsDescendant(DynamicXml other) { var ancestors = this.Ancestors(); - return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.BaseElement == other.BaseElement) != null); + return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.StrippedXmlElement == other.StrippedXmlElement) != null); } public HtmlString IsDescendant(DynamicXml other, string valueIfTrue) { var ancestors = this.Ancestors(); - return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.BaseElement == other.BaseElement) != null, valueIfTrue); + return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.StrippedXmlElement == other.StrippedXmlElement) != null, valueIfTrue); } public HtmlString IsDescendant(DynamicXml other, string valueIfTrue, string valueIfFalse) { var ancestors = this.Ancestors(); - return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.BaseElement == other.BaseElement) != null, valueIfTrue, valueIfFalse); + return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.StrippedXmlElement == other.StrippedXmlElement) != null, valueIfTrue, valueIfFalse); } public bool IsDescendantOrSelf(DynamicXml other) { var ancestors = this.AncestorsOrSelf(); - return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.BaseElement == other.BaseElement) != null); + return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.StrippedXmlElement == other.StrippedXmlElement) != null); } public HtmlString IsDescendantOrSelf(DynamicXml other, string valueIfTrue) { var ancestors = this.AncestorsOrSelf(); - return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.BaseElement == other.BaseElement) != null, valueIfTrue); + return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.StrippedXmlElement == other.StrippedXmlElement) != null, valueIfTrue); } public HtmlString IsDescendantOrSelf(DynamicXml other, string valueIfTrue, string valueIfFalse) { var ancestors = this.AncestorsOrSelf(); - return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.BaseElement == other.BaseElement) != null, valueIfTrue, valueIfFalse); + return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.StrippedXmlElement == other.StrippedXmlElement) != null, valueIfTrue, valueIfFalse); } public bool IsAncestor(DynamicXml other) { var descendants = this.Descendants(); - return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.BaseElement == other.BaseElement) != null); + return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.StrippedXmlElement == other.StrippedXmlElement) != null); } public HtmlString IsAncestor(DynamicXml other, string valueIfTrue) { var descendants = this.Descendants(); - return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.BaseElement == other.BaseElement) != null, valueIfTrue); + return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.StrippedXmlElement == other.StrippedXmlElement) != null, valueIfTrue); } public HtmlString IsAncestor(DynamicXml other, string valueIfTrue, string valueIfFalse) { var descendants = this.Descendants(); - return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.BaseElement == other.BaseElement) != null, valueIfTrue, valueIfFalse); + return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.StrippedXmlElement == other.StrippedXmlElement) != null, valueIfTrue, valueIfFalse); } public bool IsAncestorOrSelf(DynamicXml other) { var descendants = this.DescendantsOrSelf(); - return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.BaseElement == other.BaseElement) != null); + return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.StrippedXmlElement == other.StrippedXmlElement) != null); } public HtmlString IsAncestorOrSelf(DynamicXml other, string valueIfTrue) { var descendants = this.DescendantsOrSelf(); - return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.BaseElement == other.BaseElement) != null, valueIfTrue); + return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.StrippedXmlElement == other.StrippedXmlElement) != null, valueIfTrue); } public HtmlString IsAncestorOrSelf(DynamicXml other, string valueIfTrue, string valueIfFalse) { var descendants = this.DescendantsOrSelf(); - return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.BaseElement == other.BaseElement) != null, valueIfTrue, valueIfFalse); + return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.StrippedXmlElement == other.StrippedXmlElement) != null, valueIfTrue, valueIfFalse); } public IEnumerable Descendants() { @@ -653,7 +708,7 @@ namespace Umbraco.Core.Dynamics } public IEnumerable Descendants(Func func) { - var flattenedNodes = this.BaseElement.Elements().Map(func, (XElement n) => { return n.Elements(); }); + var flattenedNodes = this.StrippedXmlElement.Elements().Map(func, n => n.Elements()); return flattenedNodes.ToList().ConvertAll(n => new DynamicXml(n)); } public IEnumerable DescendantsOrSelf() @@ -662,7 +717,7 @@ namespace Umbraco.Core.Dynamics } public IEnumerable DescendantsOrSelf(Func func) { - var flattenedNodes = this.BaseElement.Elements().Map(func, (XElement n) => { return n.Elements(); }); + var flattenedNodes = this.StrippedXmlElement.Elements().Map(func, n => n.Elements()); var list = new List(); list.Add(this); list.AddRange(flattenedNodes.ToList().ConvertAll(n => new DynamicXml(n))); @@ -675,14 +730,14 @@ namespace Umbraco.Core.Dynamics public IEnumerable Ancestors(Func func) { var ancestorList = new List(); - var node = this.BaseElement; + var node = this.StrippedXmlElement; while (node != null) { if (node.Parent == null) break; XElement parent = node.Parent; if (parent != null) { - if (this.BaseElement != parent) + if (this.StrippedXmlElement != parent) { node = parent; if (func(node)) @@ -710,7 +765,7 @@ namespace Umbraco.Core.Dynamics public IEnumerable AncestorsOrSelf(Func func) { List ancestorList = new List(); - var node = this.BaseElement; + var node = this.StrippedXmlElement; ancestorList.Add(node); while (node != null) { @@ -718,7 +773,7 @@ namespace Umbraco.Core.Dynamics XElement parent = node.Parent; if (parent != null) { - if (this.BaseElement != parent) + if (this.StrippedXmlElement != parent) { node = parent; if (func(node)) @@ -742,13 +797,13 @@ namespace Umbraco.Core.Dynamics public int Index() { - if (this.BaseElement != null && this.BaseElement.Parent != null) + if (this.StrippedXmlElement != null && this.StrippedXmlElement.Parent != null) { - var elements = this.BaseElement.Parent.Elements(); + var elements = this.StrippedXmlElement.Parent.Elements(); int index = 0; foreach (var element in elements) { - if (element == this.BaseElement) break; + if (element == this.StrippedXmlElement) break; index++; } return index; diff --git a/src/Umbraco.Core/Dynamics/DynamicXmlConverter.cs b/src/Umbraco.Core/Dynamics/DynamicXmlConverter.cs index 2c3f597cd3..e021dc6852 100644 --- a/src/Umbraco.Core/Dynamics/DynamicXmlConverter.cs +++ b/src/Umbraco.Core/Dynamics/DynamicXmlConverter.cs @@ -7,6 +7,58 @@ using System.Xml.Linq; namespace Umbraco.Core.Dynamics { + /// + /// Used to return the raw xml string value from DynamicXml when using type converters + /// + public class RawXmlString + { + public string Value { get; private set; } + + public RawXmlString(string value) + { + Value = value; + } + } + + /// + /// Used to return the raw xml XElement value from DynamicXml when using type converters + /// + public class RawXElement + { + public XElement Value { get; private set; } + + public RawXElement(XElement value) + { + Value = value; + } + } + + /// + /// Used to return the raw xml XElement value from DynamicXml when using type converters + /// + public class RawXmlElement + { + public XmlElement Value { get; private set; } + + public RawXmlElement(XmlElement value) + { + Value = value; + } + } + + /// + /// Used to return the raw xml XmlDocument value from DynamicXml when using type converters + /// + public class RawXmlDocument + { + public XmlDocument Value { get; private set; } + + public RawXmlDocument(XmlDocument value) + { + Value = value; + } + } + /// /// A custom type converter for DynamicXml /// @@ -14,7 +66,17 @@ namespace Umbraco.Core.Dynamics { public override bool CanConvertTo(ITypeDescriptorContext context, Type sourceType) { - var convertableTypes = new[] {typeof(string), typeof(XElement), typeof(XmlElement), typeof(XmlDocument)}; + var convertableTypes = new[] + { + typeof(string), + typeof(XElement), + typeof(XmlElement), + typeof(XmlDocument), + typeof(RawXmlString), + typeof(RawXElement), + typeof(RawXmlElement), + typeof(RawXmlDocument) + }; return convertableTypes.Any(x => TypeHelper.IsTypeAssignableFrom(x, sourceType)) || base.CanConvertFrom(context, sourceType); @@ -34,10 +96,11 @@ namespace Umbraco.Core.Dynamics { return value.ToString(); } + //XElement if (TypeHelper.IsTypeAssignableFrom(destinationType)) { - return dxml.BaseElement; + return dxml.StrippedXmlElement; } //XmlElement if (TypeHelper.IsTypeAssignableFrom(destinationType)) @@ -53,6 +116,34 @@ namespace Umbraco.Core.Dynamics xDoc.LoadXml(dxml.ToString()); return xDoc; } + + //RAW values: + //string + if (TypeHelper.IsTypeAssignableFrom(destinationType)) + { + return new RawXmlString(dxml.ToRawXml()); + } + //XElement + if (TypeHelper.IsTypeAssignableFrom(destinationType)) + { + return new RawXElement(dxml.RawXmlElement); + } + //XmlElement + if (TypeHelper.IsTypeAssignableFrom(destinationType)) + { + var xDoc = new XmlDocument(); + xDoc.LoadXml(dxml.ToRawXml()); + return new RawXmlElement(xDoc.DocumentElement); + } + //XmlDocument + if (TypeHelper.IsTypeAssignableFrom(destinationType)) + { + var xDoc = new XmlDocument(); + xDoc.LoadXml(dxml.ToRawXml()); + return new RawXmlDocument(xDoc); + } + + return base.ConvertTo(context, culture, value, destinationType); } } diff --git a/src/Umbraco.Tests/PublishedContent/DynamicXmlConverterTests.cs b/src/Umbraco.Tests/PublishedContent/DynamicXmlConverterTests.cs index dad9649564..4f0db5ee59 100644 --- a/src/Umbraco.Tests/PublishedContent/DynamicXmlConverterTests.cs +++ b/src/Umbraco.Tests/PublishedContent/DynamicXmlConverterTests.cs @@ -10,14 +10,55 @@ namespace Umbraco.Tests.PublishedContent [TestFixture] public class DynamicXmlConverterTests : AbstractPartialTrustFixture { + [Test] + public void Convert_To_Raw_String() + { + var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; + var dXml = new DynamicXml(xml); + var result = dXml.TryConvertTo(); + Assert.IsTrue(result.Success); + Assert.AreEqual(xml, result.Result.Value); + } + + [Test] + public void Convert_To_Raw_XElement() + { + var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; + var dXml = new DynamicXml(xml); + var result = dXml.TryConvertTo(); + Assert.IsTrue(result.Success); + Assert.AreEqual(xml, result.Result.Value.ToString(SaveOptions.DisableFormatting)); + } + + [Test] + public void Convert_To_Raw_XmlElement() + { + var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; + var dXml = new DynamicXml(xml); + var result = dXml.TryConvertTo(); + Assert.IsTrue(result.Success); + Assert.AreEqual(xml, result.Result.Value.OuterXml); + } + + [Test] + public void Convert_To_Raw_XmlDocument() + { + var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; + var dXml = new DynamicXml(xml); + var result = dXml.TryConvertTo(); + Assert.IsTrue(result.Success); + Assert.AreEqual(xml, result.Result.Value.InnerXml); + } + [Test] public void Convert_To_String() { var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; var dXml = new DynamicXml(xml); + var strippedXml = dXml.ToXml(); var result = dXml.TryConvertTo(); Assert.IsTrue(result.Success); - Assert.AreEqual(xml, result.Result); + Assert.AreEqual(strippedXml, result.Result); } [Test] @@ -25,9 +66,10 @@ namespace Umbraco.Tests.PublishedContent { var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; var dXml = new DynamicXml(xml); + var strippedXml = dXml.ToXml(); var result = dXml.TryConvertTo(); Assert.IsTrue(result.Success); - Assert.AreEqual(xml, result.Result.ToString(SaveOptions.DisableFormatting)); + Assert.AreEqual(strippedXml, result.Result.ToString(SaveOptions.DisableFormatting)); } [Test] @@ -35,9 +77,10 @@ namespace Umbraco.Tests.PublishedContent { var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; var dXml = new DynamicXml(xml); + var strippedXml = dXml.ToXml(); var result = dXml.TryConvertTo(); Assert.IsTrue(result.Success); - Assert.AreEqual(xml, result.Result.OuterXml); + Assert.AreEqual(strippedXml, result.Result.OuterXml); } [Test] @@ -45,9 +88,10 @@ namespace Umbraco.Tests.PublishedContent { var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; var dXml = new DynamicXml(xml); + var strippedXml = dXml.ToXml(); var result = dXml.TryConvertTo(); Assert.IsTrue(result.Success); - Assert.AreEqual(xml, result.Result.InnerXml); + Assert.AreEqual(strippedXml, result.Result.InnerXml); } public override void TestSetup() diff --git a/src/Umbraco.Tests/PublishedContent/DynamicXmlTests.cs b/src/Umbraco.Tests/PublishedContent/DynamicXmlTests.cs index a566ce5cee..d88ef1f64b 100644 --- a/src/Umbraco.Tests/PublishedContent/DynamicXmlTests.cs +++ b/src/Umbraco.Tests/PublishedContent/DynamicXmlTests.cs @@ -30,7 +30,7 @@ namespace Umbraco.Tests.PublishedContent var typedXml = new DynamicXml(xml); dynamic dynamicXml = typedXml; - var typedElement = typedXml.BaseElement.Element("url-picker"); + var typedElement = typedXml.RawXmlElement.Element("url-picker"); var dynamicElementByCleanedName = dynamicXml.urlpicker; Assert.IsNotNull(typedElement); @@ -65,7 +65,7 @@ namespace Umbraco.Tests.PublishedContent //we haven't explicitly defined ElementAt so this will dynamically invoke this method var element = dynamicXml.ElementAt(0); - Assert.AreEqual("1057", Enumerable.First(element.BaseElement.Elements()).Attribute("id").Value); + Assert.AreEqual("1057", Enumerable.First(element.StrippedXmlElement.Elements()).Attribute("id").Value); } [Test] @@ -96,8 +96,8 @@ namespace Umbraco.Tests.PublishedContent Assert.AreEqual(1, typedTaken.Count()); Assert.AreEqual(1, Enumerable.Count(dynamicTaken)); - Assert.AreEqual("1057", typedTaken.ElementAt(0).BaseElement.Elements().First().Attribute("id").Value); - Assert.AreEqual("1057", Enumerable.First(Enumerable.ElementAt(dynamicTaken, 0).BaseElement.Elements()).Attribute("id").Value); + Assert.AreEqual("1057", typedTaken.ElementAt(0).StrippedXmlElement.Elements().First().Attribute("id").Value); + Assert.AreEqual("1057", Enumerable.First(Enumerable.ElementAt(dynamicTaken, 0).StrippedXmlElement.Elements()).Attribute("id").Value); } [Test] diff --git a/src/umbraco.MacroEngines/RazorDynamicNode/LegacyConverter.cs b/src/umbraco.MacroEngines/RazorDynamicNode/LegacyConverter.cs index 209c246003..6c2daeb0de 100644 --- a/src/umbraco.MacroEngines/RazorDynamicNode/LegacyConverter.cs +++ b/src/umbraco.MacroEngines/RazorDynamicNode/LegacyConverter.cs @@ -12,7 +12,7 @@ namespace umbraco.MacroEngines { if (result is Umbraco.Core.Dynamics.DynamicXml) { - result = new DynamicXml(((Umbraco.Core.Dynamics.DynamicXml)result).BaseElement); + result = new DynamicXml(((Umbraco.Core.Dynamics.DynamicXml)result).StrippedXmlElement); } else if (result is Umbraco.Core.Dynamics.DynamicNull) { From 3bfa1be60cd6b80581880b7266070a538ffe24d2 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Tue, 19 Feb 2013 22:14:08 +0600 Subject: [PATCH 3/3] Patch applied for #U4-1636 --- src/Umbraco.Core/Dynamics/DynamicXml.cs | 264 +++++++++--------- .../Dynamics/DynamicXmlConverter.cs | 2 +- .../DynamicXmlConverterTests.cs | 28 +- .../PublishedContent/DynamicXmlTests.cs | 11 +- .../RazorDynamicNode/LegacyConverter.cs | 2 +- 5 files changed, 161 insertions(+), 146 deletions(-) diff --git a/src/Umbraco.Core/Dynamics/DynamicXml.cs b/src/Umbraco.Core/Dynamics/DynamicXml.cs index 103128a3b6..a3f9ae7089 100644 --- a/src/Umbraco.Core/Dynamics/DynamicXml.cs +++ b/src/Umbraco.Core/Dynamics/DynamicXml.cs @@ -16,61 +16,82 @@ namespace Umbraco.Core.Dynamics [TypeConverter(typeof(DynamicXmlConverter))] public class DynamicXml : DynamicObject, IEnumerable, IEnumerable { - [Obsolete("Use StrippedXmlElement or RawXmlElement instead")] - public XElement BaseElement - { - get { return StrippedXmlElement; } - //This should have been read only but we're stuck with it now and we'll have to assume that a person is setting the 'raw' xml - set - { - Mandate.ParameterNotNull(value, "value"); - - RawXmlElement = value; - StrippedXmlElement = XElement.Parse( - XmlHelper.StripDashesInElementOrAttributeNames( - RawXmlElement.ToString())); - } - } - - /// + /// /// Returns the XElement used to create the DynamicXml structure /// + public XElement BaseElement { get; set; } + + /// + /// Returns the raw XElement used to create the DynamicXml structure if one was specified otherwise returns the + /// same value as BaseElement. + /// + /// + /// This is purely used for when an instance of DynamicXml is created with the overload that supports + /// passing in both a raw xml version and a dash-stripped xml version. Otherwise this value is exactly the + /// same as BaseElement. + /// public XElement RawXmlElement { get; internal set; } /// - /// Returns the XElement for this DynamicXml structure that has been stripped of all of it's hyphens + /// Constructor /// - public XElement StrippedXmlElement { get; private set; } - + /// public DynamicXml(XElement baseElement) { if (baseElement == null) return; + //same RawXmlElement = baseElement; - StrippedXmlElement = XElement.Parse( - XmlHelper.StripDashesInElementOrAttributeNames( - RawXmlElement.ToString())); + BaseElement = baseElement; } - internal DynamicXml(XElement rawXml, XElement strippedXml) + /// + /// When this constructor is used the BaseElement becomes equivalent to the strippedXml structure + /// + /// + /// + internal DynamicXml(XElement strippedXml, XElement rawXml) { - if (rawXml == null) throw new ArgumentNullException("rawXml"); - if (strippedXml == null) throw new ArgumentNullException("strippedXml"); + if (rawXml == null) return; + if (strippedXml == null) return; RawXmlElement = rawXml; - StrippedXmlElement = strippedXml; + BaseElement = strippedXml; } + /// + /// When this constructor is used the BaseElement becomes equivalent to the strippedXml structure + /// + /// + /// + internal DynamicXml(string strippedXml, string rawXml) + { + if (rawXml == null) return; + if (strippedXml == null) return; + + RawXmlElement = XElement.Parse(rawXml); + BaseElement = XElement.Parse(strippedXml); + } + + /// + /// Constructor + /// + /// public DynamicXml(string xml) { if (xml.IsNullOrWhiteSpace()) return; var baseElement = XElement.Parse(xml); + + //same RawXmlElement = baseElement; - StrippedXmlElement = XElement.Parse( - XmlHelper.StripDashesInElementOrAttributeNames( - xml)); + BaseElement = baseElement; } + + /// + /// Constructor + /// + /// public DynamicXml(XPathNodeIterator xpni) { if (xpni == null) return; @@ -79,34 +100,34 @@ namespace Umbraco.Core.Dynamics //TODO: OuterXml is really bad for performance! Should actually use the XPathNodeIterator api var xml = xpni.Current.OuterXml; var baseElement = XElement.Parse(xml); + + //same RawXmlElement = baseElement; - StrippedXmlElement = XElement.Parse( - XmlHelper.StripDashesInElementOrAttributeNames( - xml)); + BaseElement = baseElement; } /// - /// Returns the InnertText based on the stripped xml element + /// Returns the InnertText based on the BaseElement object /// public string InnerText { get { - return StrippedXmlElement.Value; + return BaseElement.Value; } } /// - /// Returns the string representation of the dash-stripped xml element + /// Returns the string representation of the BaseElement object /// /// public string ToXml() { - return StrippedXmlElement.ToString(SaveOptions.DisableFormatting); + return BaseElement.ToString(SaveOptions.DisableFormatting); } /// - /// Returns the string representation of the raw (no dash stripping) xml element + /// Returns the string representation of the RawXmlElement object /// /// public string ToRawXml() @@ -122,7 +143,7 @@ namespace Umbraco.Core.Dynamics index = (int)indexes[0]; result = new DynamicXml( RawXmlElement.Elements().ElementAt(index), - StrippedXmlElement.Elements().ElementAt(index)); + BaseElement.Elements().ElementAt(index)); return true; } return base.TryGetIndex(binder, indexes, out result); @@ -131,12 +152,12 @@ namespace Umbraco.Core.Dynamics { if (args.Length == 0 && binder.Name == "ToXml") { - result = StrippedXmlElement.ToString(); + result = BaseElement.ToString(); return true; } if (args.Length == 1 && binder.Name == "XPath") { - var elements = StrippedXmlElement.XPathSelectElements(args[0].ToString()); + var elements = BaseElement.XPathSelectElements(args[0].ToString()); HandleIEnumerableXElement(elements, out result); return true; //anyway } @@ -171,7 +192,7 @@ namespace Umbraco.Core.Dynamics { result = ((IEnumerable) attempt.Result.ObjectResult).Select(x => new DynamicXml( x.RawXmlElement, - x.StrippedXmlElement)); + x.BaseElement)); } } } @@ -198,8 +219,8 @@ namespace Umbraco.Core.Dynamics return false; } - //First check for matching name including the 'cleaned' name (i.e. removal of hyphens, etc... ) - var elementByNameAttempt = CheckNodeNameMatch(binder.Name, RawXmlElement, true); + //Check if the name matches a node based on the BaseElement (which if the correct ctor is used, will be dash stripped) + var elementByNameAttempt = CheckNodeNameMatch(binder.Name, BaseElement); if (elementByNameAttempt.Success) { if (HandleIEnumerableXElement(elementByNameAttempt.Result, out result)) @@ -207,9 +228,9 @@ namespace Umbraco.Core.Dynamics return true; } } - - //Ok, so no elements matched, so lets try attributes - var attributeByNameAttempt = CheckAttributeNameMatch(binder.Name, RawXmlElement, true); + + //Check if the name matches a node based on the BaseElement (which if the correct ctor is used, will be dash stripped) + var attributeByNameAttempt = CheckAttributeNameMatch(binder.Name, BaseElement); if (attributeByNameAttempt.Success) { if (attributeByNameAttempt.Result.Count() > 1) @@ -229,7 +250,13 @@ namespace Umbraco.Core.Dynamics return base.TryGetMember(binder, out result); } - private Attempt> CheckAttributeNameMatch(string name, XElement xmlElement, bool checkCleanedName) + /// + /// Checks if the 'name' matches any attributes of xmlElement + /// + /// The name to match + /// The xml element to check against + /// + private static Attempt> CheckAttributeNameMatch(string name, XElement xmlElement) { var attributes = xmlElement.Attributes(name).Select(attr => attr.Value).ToArray(); if (attributes.Any()) @@ -246,16 +273,7 @@ namespace Umbraco.Core.Dynamics //we've found a match by the first child of an element called 'root' (strange, but sure) return new Attempt>(true, childElements); } - } - - if (checkCleanedName) - { - //still no match, we'll try to match with a 'cleaned' name - var cleanedXml = StrippedXmlElement; - - //pass false in to this as we don't want an infinite loop and clean the already cleaned xml - return CheckAttributeNameMatch(name, cleanedXml, false); - } + } //no deal return Attempt>.False; @@ -266,9 +284,8 @@ namespace Umbraco.Core.Dynamics /// /// The name to match /// The xml element to check against - /// If there are no matches, we'll clean the xml (i.e. remove hyphens, etc..) and then retry /// - private Attempt> CheckNodeNameMatch(string name, XElement xmlElement, bool checkCleanedName) + private Attempt> CheckNodeNameMatch(string name, XElement xmlElement) { //Go ahead and try to fetch all of the elements matching the member name, and wrap them var elements = xmlElement.Elements(name).ToArray(); @@ -290,15 +307,6 @@ namespace Umbraco.Core.Dynamics } } - if (checkCleanedName) - { - //still no match, we'll try to match with a 'cleaned' name - var cleanedXml = StrippedXmlElement; - - //pass false in to this as we don't want an infinite loop and clean the already cleaned xml - return CheckNodeNameMatch(name, cleanedXml, false); - } - //no deal return Attempt>.False; } @@ -336,23 +344,23 @@ namespace Umbraco.Core.Dynamics } /// - /// Executes an XPath expression over the dash-stripped Xml + /// Executes an XPath expression over the BaseElement object /// /// /// public DynamicXml XPath(string expression) { - var matched = StrippedXmlElement.XPathSelectElements(expression); + var matched = BaseElement.XPathSelectElements(expression); var root = new DynamicXml(""); foreach (var element in matched) { - root.StrippedXmlElement.Add(element); + root.BaseElement.Add(element); } return root; } /// - /// Return the string version of the dash-stripped Xml + /// Return the string version of the BaseElement object /// /// public override string ToString() @@ -366,23 +374,23 @@ namespace Umbraco.Core.Dynamics } public DynamicXml Find(string expression) { - return new DynamicXml(StrippedXmlElement.XPathSelectElements(expression).FirstOrDefault()); + return new DynamicXml(BaseElement.XPathSelectElements(expression).FirstOrDefault()); } public DynamicXml Find(string attributeName, object value) { string expression = string.Format("//*[{0}='{1}']", attributeName, value); - return new DynamicXml(StrippedXmlElement.XPathSelectElements(expression).FirstOrDefault()); + return new DynamicXml(BaseElement.XPathSelectElements(expression).FirstOrDefault()); } IEnumerator IEnumerable.GetEnumerator() { - return StrippedXmlElement.Elements().GetEnumerator(); + return BaseElement.Elements().GetEnumerator(); } public IEnumerator GetEnumerator() { - return StrippedXmlElement.Elements().Select(e => new DynamicXml(e)).GetEnumerator(); + return BaseElement.Elements().Select(e => new DynamicXml(e)).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() @@ -445,7 +453,7 @@ namespace Umbraco.Core.Dynamics } public bool IsPosition(int index) { - if (StrippedXmlElement == null || StrippedXmlElement.Parent == null) + if (BaseElement == null || BaseElement.Parent == null) { return false; } @@ -453,7 +461,7 @@ namespace Umbraco.Core.Dynamics } public HtmlString IsPosition(int index, string valueIfTrue) { - if (StrippedXmlElement == null || StrippedXmlElement.Parent == null) + if (BaseElement == null || BaseElement.Parent == null) { return new HtmlString(string.Empty); } @@ -461,7 +469,7 @@ namespace Umbraco.Core.Dynamics } public HtmlString IsPosition(int index, string valueIfTrue, string valueIfFalse) { - if (StrippedXmlElement == null || StrippedXmlElement.Parent == null) + if (BaseElement == null || BaseElement.Parent == null) { return new HtmlString(valueIfFalse); } @@ -469,7 +477,7 @@ namespace Umbraco.Core.Dynamics } public bool IsModZero(int modulus) { - if (StrippedXmlElement == null || StrippedXmlElement.Parent == null) + if (BaseElement == null || BaseElement.Parent == null) { return false; } @@ -477,7 +485,7 @@ namespace Umbraco.Core.Dynamics } public HtmlString IsModZero(int modulus, string valueIfTrue) { - if (StrippedXmlElement == null || StrippedXmlElement.Parent == null) + if (BaseElement == null || BaseElement.Parent == null) { return new HtmlString(string.Empty); } @@ -485,7 +493,7 @@ namespace Umbraco.Core.Dynamics } public HtmlString IsModZero(int modulus, string valueIfTrue, string valueIfFalse) { - if (StrippedXmlElement == null || StrippedXmlElement.Parent == null) + if (BaseElement == null || BaseElement.Parent == null) { return new HtmlString(valueIfFalse); } @@ -494,7 +502,7 @@ namespace Umbraco.Core.Dynamics public bool IsNotModZero(int modulus) { - if (StrippedXmlElement == null || StrippedXmlElement.Parent == null) + if (BaseElement == null || BaseElement.Parent == null) { return false; } @@ -502,7 +510,7 @@ namespace Umbraco.Core.Dynamics } public HtmlString IsNotModZero(int modulus, string valueIfTrue) { - if (StrippedXmlElement == null || this.StrippedXmlElement.Parent == null) + if (BaseElement == null || this.BaseElement.Parent == null) { return new HtmlString(string.Empty); } @@ -510,7 +518,7 @@ namespace Umbraco.Core.Dynamics } public HtmlString IsNotModZero(int modulus, string valueIfTrue, string valueIfFalse) { - if (this.StrippedXmlElement == null || this.StrippedXmlElement.Parent == null) + if (this.BaseElement == null || this.BaseElement.Parent == null) { return new HtmlString(valueIfFalse); } @@ -518,7 +526,7 @@ namespace Umbraco.Core.Dynamics } public bool IsNotPosition(int index) { - if (this.StrippedXmlElement == null || this.StrippedXmlElement.Parent == null) + if (this.BaseElement == null || this.BaseElement.Parent == null) { return false; } @@ -526,7 +534,7 @@ namespace Umbraco.Core.Dynamics } public HtmlString IsNotPosition(int index, string valueIfTrue) { - if (this.StrippedXmlElement == null || this.StrippedXmlElement.Parent == null) + if (this.BaseElement == null || this.BaseElement.Parent == null) { return new HtmlString(string.Empty); } @@ -534,7 +542,7 @@ namespace Umbraco.Core.Dynamics } public HtmlString IsNotPosition(int index, string valueIfTrue, string valueIfFalse) { - if (this.StrippedXmlElement == null || this.StrippedXmlElement.Parent == null) + if (this.BaseElement == null || this.BaseElement.Parent == null) { return new HtmlString(valueIfFalse); } @@ -542,56 +550,56 @@ namespace Umbraco.Core.Dynamics } public bool IsLast() { - if (this.StrippedXmlElement == null || this.StrippedXmlElement.Parent == null) + if (this.BaseElement == null || this.BaseElement.Parent == null) { return false; } - int count = this.StrippedXmlElement.Parent.Elements().Count(); + int count = this.BaseElement.Parent.Elements().Count(); return IsHelper(n => n.Index() == count - 1); } public HtmlString IsLast(string valueIfTrue) { - if (this.StrippedXmlElement == null || this.StrippedXmlElement.Parent == null) + if (this.BaseElement == null || this.BaseElement.Parent == null) { return new HtmlString(string.Empty); } - int count = this.StrippedXmlElement.Parent.Elements().Count(); + int count = this.BaseElement.Parent.Elements().Count(); return IsHelper(n => n.Index() == count - 1, valueIfTrue); } public HtmlString IsLast(string valueIfTrue, string valueIfFalse) { - if (this.StrippedXmlElement == null || this.StrippedXmlElement.Parent == null) + if (this.BaseElement == null || this.BaseElement.Parent == null) { return new HtmlString(valueIfFalse); } - int count = this.StrippedXmlElement.Parent.Elements().Count(); + int count = this.BaseElement.Parent.Elements().Count(); return IsHelper(n => n.Index() == count - 1, valueIfTrue, valueIfFalse); } public bool IsNotLast() { - if (this.StrippedXmlElement == null || this.StrippedXmlElement.Parent == null) + if (this.BaseElement == null || this.BaseElement.Parent == null) { return false; } - int count = this.StrippedXmlElement.Parent.Elements().Count(); + int count = this.BaseElement.Parent.Elements().Count(); return !IsHelper(n => n.Index() == count - 1); } public HtmlString IsNotLast(string valueIfTrue) { - if (this.StrippedXmlElement == null || this.StrippedXmlElement.Parent == null) + if (this.BaseElement == null || this.BaseElement.Parent == null) { return new HtmlString(string.Empty); } - int count = this.StrippedXmlElement.Parent.Elements().Count(); + int count = this.BaseElement.Parent.Elements().Count(); return IsHelper(n => n.Index() != count - 1, valueIfTrue); } public HtmlString IsNotLast(string valueIfTrue, string valueIfFalse) { - if (this.StrippedXmlElement == null || this.StrippedXmlElement.Parent == null) + if (this.BaseElement == null || this.BaseElement.Parent == null) { return new HtmlString(valueIfFalse); } - int count = this.StrippedXmlElement.Parent.Elements().Count(); + int count = this.BaseElement.Parent.Elements().Count(); return IsHelper(n => n.Index() != count - 1, valueIfTrue, valueIfFalse); } public bool IsEven() @@ -620,87 +628,87 @@ namespace Umbraco.Core.Dynamics } public bool IsEqual(DynamicXml other) { - return IsHelper(n => n.StrippedXmlElement == other.StrippedXmlElement); + return IsHelper(n => n.BaseElement == other.BaseElement); } public HtmlString IsEqual(DynamicXml other, string valueIfTrue) { - return IsHelper(n => n.StrippedXmlElement == other.StrippedXmlElement, valueIfTrue); + return IsHelper(n => n.BaseElement == other.BaseElement, valueIfTrue); } public HtmlString IsEqual(DynamicXml other, string valueIfTrue, string valueIfFalse) { - return IsHelper(n => n.StrippedXmlElement == other.StrippedXmlElement, valueIfTrue, valueIfFalse); + return IsHelper(n => n.BaseElement == other.BaseElement, valueIfTrue, valueIfFalse); } public bool IsNotEqual(DynamicXml other) { - return IsHelper(n => n.StrippedXmlElement != other.StrippedXmlElement); + return IsHelper(n => n.BaseElement != other.BaseElement); } public HtmlString IsNotEqual(DynamicXml other, string valueIfTrue) { - return IsHelper(n => n.StrippedXmlElement != other.StrippedXmlElement, valueIfTrue); + return IsHelper(n => n.BaseElement != other.BaseElement, valueIfTrue); } public HtmlString IsNotEqual(DynamicXml other, string valueIfTrue, string valueIfFalse) { - return IsHelper(n => n.StrippedXmlElement != other.StrippedXmlElement, valueIfTrue, valueIfFalse); + return IsHelper(n => n.BaseElement != other.BaseElement, valueIfTrue, valueIfFalse); } public bool IsDescendant(DynamicXml other) { var ancestors = this.Ancestors(); - return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.StrippedXmlElement == other.StrippedXmlElement) != null); + return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.BaseElement == other.BaseElement) != null); } public HtmlString IsDescendant(DynamicXml other, string valueIfTrue) { var ancestors = this.Ancestors(); - return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.StrippedXmlElement == other.StrippedXmlElement) != null, valueIfTrue); + return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.BaseElement == other.BaseElement) != null, valueIfTrue); } public HtmlString IsDescendant(DynamicXml other, string valueIfTrue, string valueIfFalse) { var ancestors = this.Ancestors(); - return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.StrippedXmlElement == other.StrippedXmlElement) != null, valueIfTrue, valueIfFalse); + return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.BaseElement == other.BaseElement) != null, valueIfTrue, valueIfFalse); } public bool IsDescendantOrSelf(DynamicXml other) { var ancestors = this.AncestorsOrSelf(); - return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.StrippedXmlElement == other.StrippedXmlElement) != null); + return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.BaseElement == other.BaseElement) != null); } public HtmlString IsDescendantOrSelf(DynamicXml other, string valueIfTrue) { var ancestors = this.AncestorsOrSelf(); - return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.StrippedXmlElement == other.StrippedXmlElement) != null, valueIfTrue); + return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.BaseElement == other.BaseElement) != null, valueIfTrue); } public HtmlString IsDescendantOrSelf(DynamicXml other, string valueIfTrue, string valueIfFalse) { var ancestors = this.AncestorsOrSelf(); - return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.StrippedXmlElement == other.StrippedXmlElement) != null, valueIfTrue, valueIfFalse); + return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.BaseElement == other.BaseElement) != null, valueIfTrue, valueIfFalse); } public bool IsAncestor(DynamicXml other) { var descendants = this.Descendants(); - return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.StrippedXmlElement == other.StrippedXmlElement) != null); + return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.BaseElement == other.BaseElement) != null); } public HtmlString IsAncestor(DynamicXml other, string valueIfTrue) { var descendants = this.Descendants(); - return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.StrippedXmlElement == other.StrippedXmlElement) != null, valueIfTrue); + return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.BaseElement == other.BaseElement) != null, valueIfTrue); } public HtmlString IsAncestor(DynamicXml other, string valueIfTrue, string valueIfFalse) { var descendants = this.Descendants(); - return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.StrippedXmlElement == other.StrippedXmlElement) != null, valueIfTrue, valueIfFalse); + return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.BaseElement == other.BaseElement) != null, valueIfTrue, valueIfFalse); } public bool IsAncestorOrSelf(DynamicXml other) { var descendants = this.DescendantsOrSelf(); - return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.StrippedXmlElement == other.StrippedXmlElement) != null); + return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.BaseElement == other.BaseElement) != null); } public HtmlString IsAncestorOrSelf(DynamicXml other, string valueIfTrue) { var descendants = this.DescendantsOrSelf(); - return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.StrippedXmlElement == other.StrippedXmlElement) != null, valueIfTrue); + return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.BaseElement == other.BaseElement) != null, valueIfTrue); } public HtmlString IsAncestorOrSelf(DynamicXml other, string valueIfTrue, string valueIfFalse) { var descendants = this.DescendantsOrSelf(); - return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.StrippedXmlElement == other.StrippedXmlElement) != null, valueIfTrue, valueIfFalse); + return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.BaseElement == other.BaseElement) != null, valueIfTrue, valueIfFalse); } public IEnumerable Descendants() { @@ -708,7 +716,7 @@ namespace Umbraco.Core.Dynamics } public IEnumerable Descendants(Func func) { - var flattenedNodes = this.StrippedXmlElement.Elements().Map(func, n => n.Elements()); + var flattenedNodes = this.BaseElement.Elements().Map(func, n => n.Elements()); return flattenedNodes.ToList().ConvertAll(n => new DynamicXml(n)); } public IEnumerable DescendantsOrSelf() @@ -717,7 +725,7 @@ namespace Umbraco.Core.Dynamics } public IEnumerable DescendantsOrSelf(Func func) { - var flattenedNodes = this.StrippedXmlElement.Elements().Map(func, n => n.Elements()); + var flattenedNodes = this.BaseElement.Elements().Map(func, n => n.Elements()); var list = new List(); list.Add(this); list.AddRange(flattenedNodes.ToList().ConvertAll(n => new DynamicXml(n))); @@ -730,14 +738,14 @@ namespace Umbraco.Core.Dynamics public IEnumerable Ancestors(Func func) { var ancestorList = new List(); - var node = this.StrippedXmlElement; + var node = this.BaseElement; while (node != null) { if (node.Parent == null) break; XElement parent = node.Parent; if (parent != null) { - if (this.StrippedXmlElement != parent) + if (this.BaseElement != parent) { node = parent; if (func(node)) @@ -765,7 +773,7 @@ namespace Umbraco.Core.Dynamics public IEnumerable AncestorsOrSelf(Func func) { List ancestorList = new List(); - var node = this.StrippedXmlElement; + var node = this.BaseElement; ancestorList.Add(node); while (node != null) { @@ -773,7 +781,7 @@ namespace Umbraco.Core.Dynamics XElement parent = node.Parent; if (parent != null) { - if (this.StrippedXmlElement != parent) + if (this.BaseElement != parent) { node = parent; if (func(node)) @@ -797,13 +805,13 @@ namespace Umbraco.Core.Dynamics public int Index() { - if (this.StrippedXmlElement != null && this.StrippedXmlElement.Parent != null) + if (this.BaseElement != null && this.BaseElement.Parent != null) { - var elements = this.StrippedXmlElement.Parent.Elements(); + var elements = this.BaseElement.Parent.Elements(); int index = 0; foreach (var element in elements) { - if (element == this.StrippedXmlElement) break; + if (element == this.BaseElement) break; index++; } return index; diff --git a/src/Umbraco.Core/Dynamics/DynamicXmlConverter.cs b/src/Umbraco.Core/Dynamics/DynamicXmlConverter.cs index e021dc6852..f4ace38465 100644 --- a/src/Umbraco.Core/Dynamics/DynamicXmlConverter.cs +++ b/src/Umbraco.Core/Dynamics/DynamicXmlConverter.cs @@ -100,7 +100,7 @@ namespace Umbraco.Core.Dynamics //XElement if (TypeHelper.IsTypeAssignableFrom(destinationType)) { - return dxml.StrippedXmlElement; + return dxml.BaseElement; } //XmlElement if (TypeHelper.IsTypeAssignableFrom(destinationType)) diff --git a/src/Umbraco.Tests/PublishedContent/DynamicXmlConverterTests.cs b/src/Umbraco.Tests/PublishedContent/DynamicXmlConverterTests.cs index 4f0db5ee59..f0ad32a1bc 100644 --- a/src/Umbraco.Tests/PublishedContent/DynamicXmlConverterTests.cs +++ b/src/Umbraco.Tests/PublishedContent/DynamicXmlConverterTests.cs @@ -14,7 +14,9 @@ namespace Umbraco.Tests.PublishedContent public void Convert_To_Raw_String() { var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; - var dXml = new DynamicXml(xml); + var dXml = new DynamicXml( + XmlHelper.StripDashesInElementOrAttributeNames(xml), + xml); var result = dXml.TryConvertTo(); Assert.IsTrue(result.Success); Assert.AreEqual(xml, result.Result.Value); @@ -24,7 +26,9 @@ namespace Umbraco.Tests.PublishedContent public void Convert_To_Raw_XElement() { var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; - var dXml = new DynamicXml(xml); + var dXml = new DynamicXml( + XmlHelper.StripDashesInElementOrAttributeNames(xml), + xml); var result = dXml.TryConvertTo(); Assert.IsTrue(result.Success); Assert.AreEqual(xml, result.Result.Value.ToString(SaveOptions.DisableFormatting)); @@ -34,7 +38,9 @@ namespace Umbraco.Tests.PublishedContent public void Convert_To_Raw_XmlElement() { var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; - var dXml = new DynamicXml(xml); + var dXml = new DynamicXml( + XmlHelper.StripDashesInElementOrAttributeNames(xml), + xml); var result = dXml.TryConvertTo(); Assert.IsTrue(result.Success); Assert.AreEqual(xml, result.Result.Value.OuterXml); @@ -44,7 +50,9 @@ namespace Umbraco.Tests.PublishedContent public void Convert_To_Raw_XmlDocument() { var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; - var dXml = new DynamicXml(xml); + var dXml = new DynamicXml( + XmlHelper.StripDashesInElementOrAttributeNames(xml), + xml); var result = dXml.TryConvertTo(); Assert.IsTrue(result.Success); Assert.AreEqual(xml, result.Result.Value.InnerXml); @@ -55,10 +63,9 @@ namespace Umbraco.Tests.PublishedContent { var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; var dXml = new DynamicXml(xml); - var strippedXml = dXml.ToXml(); var result = dXml.TryConvertTo(); Assert.IsTrue(result.Success); - Assert.AreEqual(strippedXml, result.Result); + Assert.AreEqual(xml, result.Result); } [Test] @@ -66,10 +73,9 @@ namespace Umbraco.Tests.PublishedContent { var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; var dXml = new DynamicXml(xml); - var strippedXml = dXml.ToXml(); var result = dXml.TryConvertTo(); Assert.IsTrue(result.Success); - Assert.AreEqual(strippedXml, result.Result.ToString(SaveOptions.DisableFormatting)); + Assert.AreEqual(xml, result.Result.ToString(SaveOptions.DisableFormatting)); } [Test] @@ -77,10 +83,9 @@ namespace Umbraco.Tests.PublishedContent { var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; var dXml = new DynamicXml(xml); - var strippedXml = dXml.ToXml(); var result = dXml.TryConvertTo(); Assert.IsTrue(result.Success); - Assert.AreEqual(strippedXml, result.Result.OuterXml); + Assert.AreEqual(xml, result.Result.OuterXml); } [Test] @@ -88,10 +93,9 @@ namespace Umbraco.Tests.PublishedContent { var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; var dXml = new DynamicXml(xml); - var strippedXml = dXml.ToXml(); var result = dXml.TryConvertTo(); Assert.IsTrue(result.Success); - Assert.AreEqual(strippedXml, result.Result.InnerXml); + Assert.AreEqual(xml, result.Result.InnerXml); } public override void TestSetup() diff --git a/src/Umbraco.Tests/PublishedContent/DynamicXmlTests.cs b/src/Umbraco.Tests/PublishedContent/DynamicXmlTests.cs index d88ef1f64b..693ecf02ef 100644 --- a/src/Umbraco.Tests/PublishedContent/DynamicXmlTests.cs +++ b/src/Umbraco.Tests/PublishedContent/DynamicXmlTests.cs @@ -2,6 +2,7 @@ using System; using System.Diagnostics; using Microsoft.CSharp.RuntimeBinder; using NUnit.Framework; +using Umbraco.Core; using Umbraco.Core.Dynamics; using System.Linq; @@ -27,7 +28,9 @@ namespace Umbraco.Tests.PublishedContent "; - var typedXml = new DynamicXml(xml); + var typedXml = new DynamicXml( + XmlHelper.StripDashesInElementOrAttributeNames(xml), + xml); dynamic dynamicXml = typedXml; var typedElement = typedXml.RawXmlElement.Element("url-picker"); @@ -65,7 +68,7 @@ namespace Umbraco.Tests.PublishedContent //we haven't explicitly defined ElementAt so this will dynamically invoke this method var element = dynamicXml.ElementAt(0); - Assert.AreEqual("1057", Enumerable.First(element.StrippedXmlElement.Elements()).Attribute("id").Value); + Assert.AreEqual("1057", Enumerable.First(element.BaseElement.Elements()).Attribute("id").Value); } [Test] @@ -96,8 +99,8 @@ namespace Umbraco.Tests.PublishedContent Assert.AreEqual(1, typedTaken.Count()); Assert.AreEqual(1, Enumerable.Count(dynamicTaken)); - Assert.AreEqual("1057", typedTaken.ElementAt(0).StrippedXmlElement.Elements().First().Attribute("id").Value); - Assert.AreEqual("1057", Enumerable.First(Enumerable.ElementAt(dynamicTaken, 0).StrippedXmlElement.Elements()).Attribute("id").Value); + Assert.AreEqual("1057", typedTaken.ElementAt(0).BaseElement.Elements().First().Attribute("id").Value); + Assert.AreEqual("1057", Enumerable.First(Enumerable.ElementAt(dynamicTaken, 0).BaseElement.Elements()).Attribute("id").Value); } [Test] diff --git a/src/umbraco.MacroEngines/RazorDynamicNode/LegacyConverter.cs b/src/umbraco.MacroEngines/RazorDynamicNode/LegacyConverter.cs index 6c2daeb0de..6a68cf1a82 100644 --- a/src/umbraco.MacroEngines/RazorDynamicNode/LegacyConverter.cs +++ b/src/umbraco.MacroEngines/RazorDynamicNode/LegacyConverter.cs @@ -12,7 +12,7 @@ namespace umbraco.MacroEngines { if (result is Umbraco.Core.Dynamics.DynamicXml) { - result = new DynamicXml(((Umbraco.Core.Dynamics.DynamicXml)result).StrippedXmlElement); + result = new DynamicXml(((Umbraco.Core.Dynamics.DynamicXml)result).BaseElement); } else if (result is Umbraco.Core.Dynamics.DynamicNull) {