/// <summary> /// Performs a custom equals test against two configured name objects using value semantics over the local name and namespace URI. /// </summary> /// <param name="a"> The first configured name to test. </param> /// <param name="b"> The second configured name object to test. </param> /// <returns> A value indicating whether the two configured name objects are equal using value semantics. </returns> private static bool TestEquals(XyzlName a, XyzlName b) { return((a.LocalName == b.LocalName) && (a.NamespaceUri == b.NamespaceUri)); }
public async ValueTask <ISolderConfiguration> DeserializeAsync(XmlReader xmlReader, CancellationToken cancellationToken = default) { IXyzlName elementXyzlName = null, attributeXyzlName, previousElementXyzlName; ISolderConfiguration documentSolderConfiguration = null; ISolderConfiguration currentSolderConfiguration; Stack <ISolderConfiguration> contextStack; bool isEmptyElement, isTextElement; Dictionary <IXyzlName, string> attributes; IXmlLineInfo xmlLineInfo; if ((object)xmlReader == null) { throw new ArgumentNullException(nameof(xmlReader)); } // setup contextual data attributes = new Dictionary <IXyzlName, string>(); contextStack = new Stack <ISolderConfiguration>(); xmlLineInfo = xmlReader as IXmlLineInfo; // walk the XML document while (await xmlReader.ReadAsync()) { // determine node type if (xmlReader.NodeType == XmlNodeType.CDATA || xmlReader.NodeType == XmlNodeType.Text) // textual node { // clear previous attributes attributes.Clear(); // is this a text element? isTextElement = this.IsTextElement(contextStack, elementXyzlName ?? new XyzlName()); // get the current XML configuration object as XML text object currentSolderConfiguration = this.DeserializeFromXmlText(xmlLineInfo, contextStack, xmlReader.Value, isTextElement ? elementXyzlName : null); // is this a text element? if so, deserialize into it in a special maner if (isTextElement) { this.DeserializeFromXml(xmlLineInfo, contextStack, null, elementXyzlName, attributes, (IXyzlValue <string>)currentSolderConfiguration); } } else if (xmlReader.NodeType == XmlNodeType.Element) // actual elements { // DebugWrite(string.Format("{2} <{0}{1}>", xmlReader.LocalName, xmlReader.IsEmptyElement ? " /" : string.Empty, xmlReader.IsEmptyElement ? "empty" : "begin")); // stash away previous element //previousElementXyzlName = elementXyzlName; // fixes a bug here if (contextStack.Count > 0) { previousElementXyzlName = this.GetConfiguredName(contextStack.Peek()); } else { previousElementXyzlName = null; } // create the element XML name elementXyzlName = new XyzlName() { LocalName = xmlReader.LocalName, NamespaceUri = xmlReader.NamespaceURI }; // is this an empty element? isEmptyElement = xmlReader.IsEmptyElement; // is this a text element? isTextElement = this.IsTextElement(contextStack, elementXyzlName); // clear previous attributes attributes.Clear(); // iterate over attributes of current element for (int ai = 0; ai < xmlReader.AttributeCount; ai++) { // traverse to next attribute xmlReader.MoveToAttribute(ai); // create the attribute XML name attributeXyzlName = new XyzlName() { LocalName = xmlReader.LocalName, NamespaceUri = xmlReader.NamespaceURI }; // append to attribute collection attributes.Add(attributeXyzlName, xmlReader.Value); } // clear attribute name attributeXyzlName = null; // is this not a text element? if (!isTextElement) { // deserialize current XML configuration object currentSolderConfiguration = this.DeserializeFromXml(xmlLineInfo, contextStack, previousElementXyzlName, elementXyzlName, attributes, null); } else { // use 'dummy' current XML configuration object (the parent so depth counts are correct and IsTextElement() works) currentSolderConfiguration = contextStack.Peek(); } // check context stack depth for emptiness if (contextStack.Count <= 0) { // document element is current element when no context present documentSolderConfiguration = currentSolderConfiguration; } // push current XML configuration object as parent XML configuration object if there are children possible (no empty element) if (!isEmptyElement) { contextStack.Push(currentSolderConfiguration); } } else if (xmlReader.NodeType == XmlNodeType.EndElement) // closing element { // DebugWrite(string.Format("end <{0}>", xmlReader.LocalName)); // create the element XML name elementXyzlName = new XyzlName() { LocalName = xmlReader.LocalName, NamespaceUri = xmlReader.NamespaceURI }; // is this a text element? isTextElement = this.IsTextElement(contextStack, elementXyzlName); // sanity check if (contextStack.Count < 1) { throw new XyzlException(string.Format("TODO: error message")); } // pop element off stack (unwind) contextStack.Pop(); // clear attribute name elementXyzlName = null; } } // sanity check if (contextStack.Count != 0) { throw new XyzlException(string.Format("TODO: error message")); } // ...and I'm spent! return(documentSolderConfiguration); }