I made a little model class for a macro, this contains the name of the macro and a dictionary of its properties.
public class UmbracoMacro { public string Name { get; set; } public IDictionary<string, object> Properties { get; set; } }
I then created a class that would convert the macro string into the UmbracoMacro object I created.
public class MacroTagParser { public static UmbracoMacro GetMacroFromTag(string tag) { var sb = new StringBuilder(); var macro = new UmbracoMacro(); ParseMacros( tag, textBlock => sb.Append(textBlock), (macroAlias, macroAttributes) => macro = new UmbracoMacro { Name = macroAlias, Properties = ConvertTo(macroAttributes, x => (string)x, x => (object)x) } ); return macro; } public static IDictionary<TKeyOut, TValOut> ConvertTo<TKeyOut, TValOut>(IDictionary d, Func<object, TKeyOut> keyConverter, Func<object, TValOut> valConverter) { var result = new Dictionary<TKeyOut, TValOut>(); foreach (DictionaryEntry v in d) { result.Add(keyConverter(v.Key), valConverter(v.Value)); } return result; } internal static void ParseMacros( string text, Action<string> textFoundCallback, Action<string, Dictionary<string, string>> macroFoundCallback) { if (textFoundCallback == null) throw new ArgumentNullException("textFoundCallback"); if (macroFoundCallback == null) throw new ArgumentNullException("macroFoundCallback"); string elementText = text; var fieldResult = new StringBuilder(elementText); //NOTE: This is legacy code, this is definitely not the correct way to do a while loop! :) var stop = false; while (!stop) { var tagIndex = fieldResult.ToString().ToLower().IndexOf("<?umbraco"); if (tagIndex < 0) tagIndex = fieldResult.ToString().ToLower().IndexOf("<umbraco:macro"); if (tagIndex > -1) { var tempElementContent = ""; //text block found, call the call back method textFoundCallback(fieldResult.ToString().Substring(0, tagIndex)); fieldResult.Remove(0, tagIndex); var tag = fieldResult.ToString().Substring(0, fieldResult.ToString().IndexOf(">") + 1); var attributes = XmlHelper.GetAttributesFromElement(tag); // Check whether it's a single tag (<?.../>) or a tag with children (<?..>...</?...>) if (tag.Substring(tag.Length - 2, 1) != "/" && tag.IndexOf(" ") > -1) { String closingTag = "</" + (tag.Substring(1, tag.IndexOf(" ") - 1)) + ">"; // Tag with children are only used when a macro is inserted by the umbraco-editor, in the // following format: "<?UMBRACO_MACRO ...><IMG SRC="..."..></?UMBRACO_MACRO>", so we // need to delete extra information inserted which is the image-tag and the closing // umbraco_macro tag if (fieldResult.ToString().IndexOf(closingTag) > -1) { fieldResult.Remove(0, fieldResult.ToString().IndexOf(closingTag)); } } var macroAlias = attributes.ContainsKey("macroalias") ? attributes["macroalias"] : attributes["alias"]; //call the callback now that we have the macro parsed macroFoundCallback(macroAlias, attributes); fieldResult.Remove(0, fieldResult.ToString().IndexOf(">") + 1); fieldResult.Insert(0, tempElementContent); } else { //text block found, call the call back method textFoundCallback(fieldResult.ToString()); stop = true; //break; } } } }
To use it in a macro I just do this:
var hack = Umbraco.Field("macroName").ToString(); var macro = Samson.Model.UmbracoHelpers.MacroTagParser.GetMacroFromTag(hack); @Umbraco.RenderMacro(macro.Name, macro.Properties);
I imagine that I have just done something wrong which has caused the error to occur, but just incase it isn't just me, I thought I'd put this online in case others are in need for it.
Update
Turns out there is an easier way. In the Umbraco Library helpers there is this method that can be used to display the macros from a macro container.
@Html.Raw(umbraco.library.RenderMacroContent(CurrentPage.{nameOfPageField}, CurrentPage.Id))
Comments
comments powered by Disqus