protected XmlObservableParser(bool caseSensitive)
        {
            comparer = caseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase;

            id = Character(char.IsLetter)
                 .And(
                Character(char.IsLetterOrDigit).NoneOrMore())
                 .Join();

            const char tagStartChar = '<';
            const char tagEndChar   = '>';

            tagStart = Character(tagStartChar);
            tagEnd   = Character(tagEndChar);

            tagName = id;

            openTag = (namePredicate, attributes) =>
                      from _ in tagStart
                      from name in tagName.Where(namePredicate)
                      from attrs in attributes
                      from __ in InsignificantWhiteSpace
                      from empty in Character('/').Maybe()
                      from ___ in tagEnd
                      select Tuple.Create(name, attrs, empty.Any());

            attributeDelimiter = Character('\'').Or(Character('"'));

            attributeName = id;

            attributeValue = from delimeter in attributeDelimiter
                             from value in AnyCharacterUntil(delimeter)
                             from _ in Character(delimeter)
                             select value;

            attribute = predicate => from _ in InsignificantWhiteSpace
                        from name in attributeName.Where(predicate)
                        from __ in InsignificantWhiteSpace
                        from ___ in Character('=')
                        from ____ in InsignificantWhiteSpace
                        from value in attributeValue
                        select new XAttribute(name, value);

            closeTag = from _ in tagStart.And(Character('/'))
                       from name in tagName
                       from __ in InsignificantWhiteSpace
                       from ___ in tagEnd
                       select name;

            text = AnyCharacterUntil(tagStartChar).Select(t => new XText(t));

            comment = from _ in Word(tagStartChar + "!--")
                      from value in AnyCharacterUntil("--")
                      from __ in Word("--" + tagEndChar)
                      select new XComment(value);

            string startCData = tagStartChar + "![CDATA[";
            string endCData   = "]]" + tagEndChar;

            cData = from _ in Word(startCData)
                    from value in AnyCharacterUntil(endCData)
                    from __ in Word(endCData)
                    select new XCData(value);

            element = (namePredicate, attributes, elementContent) =>
                      from _ in InsignificantWhiteSpace
                      let open = openTag(namePredicate, attributes)
                                 from tag in open
                                 from isEmpty in tag.Item3
                                 from children in isEmpty
          ? open.Success(Observable.Empty <XObject>())
          : elementContent.IgnoreTrailing(
                InsignificantWhiteSpace.IgnoreBefore(
                    closeTag))
                                 from array in tag.Item2.Concat(children).ToArray()
                                 select new XElement(tag.Item1, array);
        }