public RenderState(RenderState copy, TreePathStreamedBlob item = null) { this.engine = copy.engine; this.item = item ?? copy.item; this.readFrom = copy.readFrom; this.writeTo = copy.writeTo; this.earlyExit = copy.earlyExit; this.processElements = copy.processElements; this.previous = copy; }
public RenderState(ContentEngine engine, TreePathStreamedBlob item, XmlTextReader readFrom = null, StringBuilder writeTo = null, Func<RenderState, bool> earlyExit = null, Func<RenderState, Task<Errorable<bool>>> processElements = null, RenderState previous = null) { this.engine = engine; this.item = item; this.readFrom = readFrom; this.writeTo = writeTo; this.earlyExit = earlyExit ?? DefaultEarlyExit; this.processElements = processElements ?? DefaultProcessElements; this.previous = previous; }
public static bool DefaultEarlyExit(RenderState st) { return false; }
public static async Task<Errorable> ProcessCMSInstruction(string elementName, RenderState state) { string openingElement = state.readFrom.LocalName; int openingDepth = state.readFrom.Depth; bool openingEmpty = state.readFrom.IsEmptyElement; // Run the cms- element name through the custom-element provider chain: ICustomElementProvider provider = state.engine.CustomElementProviderRoot; // Run down the chain until a provider picks up the element and processes its contents: bool processed = false; while (provider != null) { Errorable<bool> eprocessed = await provider.ProcessCustomElement(elementName, state).ConfigureAwait(continueOnCapturedContext: false); if (eprocessed.HasErrors) return eprocessed.Errors; processed = eprocessed.Value; if (processed) break; provider = provider.Next; } if (!processed) { // Unrecognized 'cms-' element name, skip its contents entirely. // Validate that the XmlTextReader is at the same state before the processor chain was invoked: // This is to detect bad custom element processors that attempt to affect state when they report // they have not. // We must be at the same element of the custom instruction: if (state.readFrom.NodeType != XmlNodeType.Element) state.Error("custom element provider left XML parser on an unexpected node type"); // The element name must be the same: if (state.readFrom.LocalName != openingElement) state.Error("custom element provider left XML parser on an unexpected end element"); // The depth level must be the same: if (state.readFrom.Depth != openingDepth) state.Error("custom element provider left XML parser at an unexpected depth level"); // Issue a warning: state.WarningSuppressComment("No custom element providers processed unknown element, '{0}'; skipping its contents entirely.", openingElement); state.SkipElementAndChildren(elementName); return Errorable.NoErrors; } // We must be at the end (or same, if empty) element of the custom instruction: if (state.readFrom.NodeType != (openingEmpty ? XmlNodeType.Element : XmlNodeType.EndElement)) state.Error("custom element provider left XML parser on an unexpected node type"); // The element name must be the same: if (state.readFrom.LocalName != openingElement) state.Error("custom element provider left XML parser on an unexpected end element"); // The depth level must be the same: if (state.readFrom.Depth != openingDepth) state.Error("custom element provider left XML parser at an unexpected depth level"); return Errorable.NoErrors; }
public static async Task<Errorable<bool>> DefaultProcessElements(RenderState st) { if (st.Reader == null) throw new InvalidOperationException(); if (st.Writer == null) throw new InvalidOperationException(); if (st.Reader.NodeType == XmlNodeType.Element && st.Reader.LocalName.StartsWith("cms-")) { // Call out to the custom element handlers: var err = await ProcessCMSInstruction(st.Reader.LocalName, st).ConfigureAwait(continueOnCapturedContext: false); if (err.HasErrors) return err.Errors; // Skip normal copying behavior for this element: return false; } return true; }