protected static XElement SetRowSeats(SeatPattern seatPattern, SeatsOrder seatsOrder, string rowName,
            IEnumerable<DataRow> filteredSeats, XElement currentElement)
        {
            currentElement.SetAttributeValue("data-row", rowName);

            // TODO : Verify this is always true: what if rows shouldn't always be left o right
            currentElement.ReorderElements(OrderBy.MinX);

            var currentPathElement = currentElement.Descendants().First();

            var rowSeats = GetOrderedSeatsForRow(filteredSeats, rowName, seatsOrder);
            switch (seatPattern)
            {
                case SeatPattern.Odds:
                    rowSeats = rowSeats.Where(x => int.Parse(x["seat_num"].ToString())%2 != 0);
                    break;
                case SeatPattern.Even:
                    rowSeats = rowSeats.Where(x => int.Parse(x["seat_num"].ToString())%2 == 0);
                    break;
            }

            foreach (var seat in rowSeats)
            {
                currentPathElement = SetElementAndGetNext(currentPathElement, seat);
                if (currentPathElement == null) break;
            }

            currentElement = currentElement.ElementsAfterSelf().FirstOrDefault();
            return currentElement;
        }
        /// <summary>
        ///   Parses the specified notification element.
        /// </summary>
        /// <param name = "notificationElement">The notification element.</param>
        /// <returns></returns>
        public ConstantEntity Parse(TypedEntity typedEntity, XElement notificationElement)
        {
            ConstantEntity notificationEntity = new ConstantEntity();
            notificationEntity.Type = "NSString";

            // Get the name
            notificationEntity.Name = notificationElement.TrimAll();

            this.Logger.WriteLine("  Notification '" + notificationEntity.Name + "'");

            // Get the content and the discussion
            XElement summaryElement = (from el in notificationElement.ElementsAfterSelf("section")
                                       where (String) el.Attribute("class") == "spaceabove"
                                       select el).FirstOrDefault();
            if (summaryElement != null)
            {
                foreach (XElement element in summaryElement.Elements())
                {
                    notificationEntity.Summary.Add(element.Value.TrimAll());
                }
            }

            // Get the availability
            String minAvailability = (from el in notificationElement.ElementsAfterSelf("div").Elements("ul").Elements("li")
                                      where (String) el.Parent.Parent.Attribute("class") == "api availability"
                                      select el.Value).FirstOrDefault();
            notificationEntity.MinAvailability = CommentHelper.ExtractAvailability(minAvailability.TrimAll());

            return notificationEntity;
        }
        /// <summary>
        ///   Parses the specified constant element.
        /// </summary>
        /// <param name = "constantElement">The constant element.</param>
        public List<BaseEntity> Parse(TypedEntity typedEntity, XElement constantElement)
        {
            // Get the name
            String name = constantElement.TrimAll ();

            // Get the abstract
            XElement summaryElement = (from el in constantElement.ElementsAfterSelf ("p")
                                       where (String)el.Attribute ("class") == "abstract"
                                       select el).FirstOrDefault ();
            String summary = summaryElement.TrimAll ();

            // Get the declaration
            XElement declarationElement = (from el in constantElement.ElementsAfterSelf ("pre")
                                           where (String)el.Attribute ("class") == "declaration"
                                           select el).FirstOrDefault ();
            String declaration = declarationElement.TrimAll ();

            // Make various tests
            bool isDefine = declaration.StartsWith ("#define");
            bool isEnum = declaration.StartsWith ("enum") || declaration.StartsWith ("typedef enum") || declaration.Contains (" enum ");

            if (isDefine) {
                List<BaseEntity> entities = ExtractDefine (constantElement, name, summary, declaration);
                return entities;
            }

            if (isEnum) { // keep newlines for enum processing
                List<BaseEntity> entities = this.ExtractEnumeration (constantElement, name, summary, declarationElement.TrimSpaces());
                if (entities != null) {
                    return entities;
                }
            }

            return this.ExtractConstants (constantElement, name, summary, declaration);
        }
 public static IEnumerable<XElement> NextSdtElements(XElement startElement, IEnumerable<XName> names)
 {
     var namesList = names.ToList();
     var nextTagsInnerElements = GoDeeper(startElement, namesList).ToList();
     if (nextTagsInnerElements.Any())
     {
         return nextTagsInnerElements;
     }
     if (startElement == null)
     {
         throw new ArgumentNullException("startElement");
     }
     var nextTagElements = startElement.ElementsAfterSelf().Where(MakeSdtMatchingPredicate(namesList)).ToList();
     return nextTagElements.Any() ? nextTagElements : GoUp(startElement, namesList);
 }
 public static IEnumerable<XElement> NextTagElements(XElement startElement, IEnumerable<string> tagNames)
 {
     if (startElement == null)
     {
         throw new ArgumentNullException(string.Format("Argument {0} cannot be null", "startElement"));
     }
     if (tagNames == null)
     {
         throw new ArgumentNullException(string.Format("Argument {0} cannot be null", "tagNames"));
     }
     var namesList = tagNames.Select(s => s.ToLower()).ToList();
     var nextTagsInnerElements = GoDeeper(startElement, namesList).ToList();
     if (nextTagsInnerElements.Any())
     {
         return nextTagsInnerElements;
     }
     var nextTagElements = startElement.ElementsAfterSelf(WordMl.SdtName).Where(MakeTagMatchingPredicate(namesList)).ToList();
     return nextTagElements.Any() ? nextTagElements : GoUp(startElement, namesList);
 }
 public static IEnumerable<XElement> ElementsBetween(XElement startElement, XElement endElement)
 {
     if (startElement == null)
     {
         throw new ArgumentNullException("startElement");
     }
     if (endElement == null)
     {
         throw new ArgumentNullException("endElement");
     }
     if (startElement.Parent.Equals(endElement.Parent))
     {
         return startElement.ElementsAfterSelf().Where(e => e.IsBefore(endElement));               
     }
     var commonParent = startElement.Ancestors().Intersect(endElement.Ancestors()).FirstOrDefault();
     if (commonParent == null)
     {
         return Enumerable.Empty<XElement>();
     }
     var endElementFirstLevel = commonParent.Elements().First(e => e.Descendants().Contains(endElement) || e.Equals(endElement));
     var startElementFirstLevel = commonParent.Elements().First(e => e.Descendants().Contains(startElement) || e.Equals(startElement));
     var afterStart = startElement.ElementsAfterSelf();
     var between = ElementsBetween(startElementFirstLevel, endElementFirstLevel);
     var beforeEnd = endElementFirstLevel.DescendantsBefore(endElement);
     return afterStart.Union(between).Union(beforeEnd);
 }
        private static IEnumerable<XElement> GoDeeper(XElement startElement, ICollection<XName> names)
        {
            if (startElement == null)
            {
                throw new ArgumentNullException("startElement");
            }
            if (names == null)
            {
                throw new ArgumentNullException("names");
            }
            var tagsElements = startElement.Descendants().Where(MakeSdtMatchingPredicate(names)).ToList();
            var isAnyTagsElement = tagsElements.Any();

            return isAnyTagsElement
                       ? tagsElements
                       : startElement.ElementsAfterSelf()
                                     .DescendantsAndSelf()
                                     .Where(MakeSdtMatchingPredicate(names));

        }
 // TODO make one second elements between       
 public static IEnumerable<XElement> SecondElementsBetween(XElement startElement, XElement endElement, bool nested = false)
 {
     if (startElement == null)
     {
         throw new ArgumentNullException("startElement");
     }
     if (endElement == null)
     {
         throw new ArgumentNullException("endElement");
     }
     if (startElement.Equals(endElement))
     {
         return Enumerable.Empty<XElement>();
     }
     if (startElement.Parent.Equals(endElement.Parent))
     {                
         var oneLevelElements = new List<XElement>();
         if (nested)
         {
             oneLevelElements.Add(startElement);
         }
         oneLevelElements.AddRange(startElement.ElementsAfterSelf().Where(e => e.IsBefore(endElement)));                
         return oneLevelElements.AsEnumerable();               
     }
     var currentElement = startElement.NextElementWithUpTransition();
     var elements = new List<XElement>();
     while ((currentElement != null) && (currentElement != endElement))
     {
         if (currentElement.HasElements && currentElement.Descendants().Contains(endElement))
         {
             elements.AddRange(SecondElementsBetween(currentElement.Elements().First(), endElement, true));
             break;                    
         }
         elements.Add(currentElement);
         currentElement = currentElement.NextElementWithUpTransition();
     }
     return elements;
 }
Esempio n. 9
0
        public void NodeElementsAfterSelf()
        {
            XElement parent = new XElement("parent");

            XElement child1a = new XElement("child1", new XElement("nested"));
            XElement child1b = new XElement("child1", new XElement("nested"));
            XElement child2a = new XElement("child2", new XElement("nested"));
            XElement child2b = new XElement("child2", new XElement("nested"));

            XComment comment = new XComment("this is a comment");

            // If no parent, should not be any elements before it.
            Assert.Empty(comment.ElementsAfterSelf());

            parent.Add(child1a);
            parent.Add(comment);
            parent.Add(child1b);
            parent.Add(child2a);
            parent.Add(child2b);

            Assert.Equal(new XElement[] { child1b, child2a, child2b }, comment.ElementsAfterSelf());

            Assert.Equal(new XElement[] { child1b }, comment.ElementsAfterSelf("child1"));

            Assert.Equal(new XElement[] { child1b }, child1a.ElementsAfterSelf("child1"));

            Assert.Empty(child2b.ElementsAfterSelf());
        }
        private List<BaseEntity> ExtractEnumeration(XElement constantElement, String name, String summary, String declaration)
        {
            declaration = declaration.Trim (';');

            // Default values
            String type = "NOTYPE";
            String values = String.Empty;

            // Match the enumeration definition
            bool result = this.SplitEnumeration (declaration, ref name, ref type, ref values);
            if (!result) {
                return null;
            }

            if (type == "NOTYPE") {
                type = RefineEnumBaseType(values);
            }

            // Create the enumeration
            EnumerationEntity enumerationEntity = new EnumerationEntity ();
            enumerationEntity.Name = name;
            enumerationEntity.BaseType = type;
            enumerationEntity.Namespace = "MISSING";
            enumerationEntity.Summary.Add (summary);

            // Parse the values
            var pairs = values.Split (new []{'\n'}, StringSplitOptions.RemoveEmptyEntries);
            foreach (string immutablePair in pairs) {
                String key;
                String value = String.Empty;
                String pair = immutablePair.Replace(",","");

                // Handle value assignment
                if (pair.IndexOf ('=') != -1) {
                    string[] parts = pair.Split (new []{'='}, StringSplitOptions.RemoveEmptyEntries);
                    key = parts [0].Trim ();
                    value = parts [1].Trim ();
                } else {
                    key = pair.Trim ();
                }

                // Add a new value
                EnumerationValueEntity enumerationValueEntity = new EnumerationValueEntity ();
                enumerationValueEntity.Name = key;

                if (value.Length == 6 && value.StartsWith ("'") && value.EndsWith ("'")) {
                    String v = value.Trim ('\'');
                    enumerationValueEntity.Value = "0x" + FourCharToInt (v).ToString ("X8");
                } else {
                    enumerationValueEntity.Value = value;
                }

                // Convert number qualifiers from native to managed
                enumerationValueEntity.Value = ConvertNumericQualifier (enumerationValueEntity.Value);

                enumerationEntity.Values.Add (enumerationValueEntity);
            }

            // Get the definitions
            XElement termList = (from el in constantElement.ElementsAfterSelf ("dl")
                                 where (String)el.Attribute ("class") == "termdef"
                                 select el).FirstOrDefault ();
            if (termList != null) {
                IEnumerable<XElement> dtList = termList.Elements ("dt");
                IEnumerable<XElement> ddList = termList.Elements ("dd");

                if (dtList.Count () == ddList.Count ()) {
                    // Iterate over definitions
                    for (int i = 0; i < dtList.Count(); i++) {
                        String term = dtList.ElementAt (i).Value.TrimAll ();
                        IEnumerable<String> summaries = ddList.ElementAt (i).Elements ("p").Select (p => p.Value.TrimAll ());

                        // Find the enumeration value
                        EnumerationValueEntity enumerationValueEntity = enumerationEntity.Values.Find (v => v.Name == term);
                        if (enumerationValueEntity != null) {
                            foreach (string sum in summaries) {
                                if (CommentHelper.IsAvailability (sum)) {
                                    enumerationValueEntity.MinAvailability = CommentHelper.ExtractAvailability (sum);
                                    break;
                                }
                                enumerationValueEntity.Summary.Add (sum);
                            }
                        } else {
                            this.Logger.WriteLine ("Term with no match '" + term + "'");
                        }
                    }
                } else {
                    this.Logger.WriteLine ("MISMATCH in terms");
                }
            }

            // Make sure availability is ok
            enumerationEntity.AdjustAvailability ();

            return new List<BaseEntity> {enumerationEntity};
        }
        private List<BaseEntity> ExtractConstants(XElement constantElement, String name, String summary, String declaration)
        {
            List<BaseEntity> constants = new List<BaseEntity> ();

            // Extract types and names
            string[] declarations = declaration.Split (new []{';'}, StringSplitOptions.RemoveEmptyEntries);
            foreach (string part in declarations) {
                //this.Logger.WriteLine("Parsing constant '{0}'...", part.Trim());

                String stripped = part.Trim ();
                stripped = stripped.Replace ("extern", String.Empty);
                stripped = stripped.Replace ("const", String.Empty);
                stripped = stripped.TrimAll ();

                Match r = CONSTANT_REGEX.Match (stripped);
                if (r.Success) {
                    String type = r.Groups [1].Value.Trim (' ', '*', ' ');

                    bool isOut;
                    bool isByRef;
                    bool isBlock;
                    type = this.TypeManager.ConvertType (type, out isOut, out isByRef, out isBlock, this.Logger);

                    ConstantEntity constantEntity = new ConstantEntity ();
                    constantEntity.Type = type;
                    constantEntity.Name = r.Groups [2].Value.Trim ();
                    constants.Add (constantEntity);

                    //this.Logger.WriteLine("Constant found '{0}' of type '{1}'", constantEntity.Name, constantEntity.Type);
                } else {
                    this.Logger.WriteLine ("FAILED to parse constant '{0}'", stripped);
                    return null;
                }
            }

            // Get the definitions
            XElement termDefinitions = (from el in constantElement.ElementsAfterSelf ("dl")
                                        where (String)el.Attribute ("class") == "termdef"
                                        select el).FirstOrDefault ();
            if (termDefinitions == null) {
                this.Logger.WriteLine ("MISSING terms");
                return null;
            }

            IEnumerable<XElement> termName = termDefinitions.Elements ("dt");
            IEnumerable<XElement> termDefinition = termDefinitions.Elements ("dd");

            if (termName.Count () == termDefinition.Count ()) {
                // Iterate over definitions
                for (int i = 0; i < termName.Count(); i++) {
                    String term = termName.ElementAt (i).Value.TrimAll ();
                    IEnumerable<String> summaries = termDefinition.ElementAt (i).Elements ("p").Select (p => p.Value.TrimAll ());

                    // Find the enumeration value
                    BaseEntity baseEntity = constants.Find (c => c.Name == term);
                    if (baseEntity != null) {
                        foreach (string sum in summaries) {
                            if (CommentHelper.IsAvailability (sum)) {
                                baseEntity.MinAvailability = CommentHelper.ExtractAvailability (sum);
                                break;
                            }
                            baseEntity.Summary.Add (sum);
                        }
                    } else {
                        this.Logger.WriteLine ("Term with no match '" + term + "'");
                    }
                }
            } else {
                this.Logger.WriteLine ("MISMATCH in terms");
                return null;
            }

            return constants;
        }
Esempio n. 12
0
        private static string GetNameWithIndex(XElement element)
        {
            // numbering starts with 1
            var index = element.ElementsBeforeSelf(element.Name).Count() + 1;

            // add index only when there are more then 1 elements
            if (index == 1 && !element.ElementsAfterSelf(element.Name).Any()) return element.Name.ToString();

            return element.Name + "[" + index + "]";;
        }
Esempio n. 13
0
 public bool IsRepeated(XElement element)
 {
     return element.ElementsAfterSelf(Name).Any();
 }
        /// <summary>
        ///   Parses the specified method element.
        /// </summary>
        /// <param name = "functionElement">The function element.</param>
        /// <returns></returns>
        public FunctionEntity Parse(TypedEntity typedEntity, XElement functionElement)
        {
            FunctionEntity functionEntity = new FunctionEntity ();

            // Extract name
            String name = functionElement.TrimAll ();
            functionEntity.Name = name;

            this.Logger.WriteLine ("  Function '" + name + "'");

            // Extract abstract
            XElement abstractElement = (from el in functionElement.ElementsAfterSelf ("p")
                                        where (String)el.Attribute ("class") == "abstract"
                                        select el).FirstOrDefault ();
            functionEntity.Summary.Add (abstractElement.TrimAll ());

            // Extract declaration
            XElement declarationElement = (from el in functionElement.ElementsAfterSelf ("pre")
                                           where (String)el.Attribute ("class") == "declaration"
                                           select el).FirstOrDefault ();

            String signature = declarationElement.TrimAll ();
            if (signature.StartsWith ("#define")) {
                this.Logger.WriteLine ("SKIPPING define statement: " + name);
                return null;
            }
            if (signature.StartsWith ("typedef")) {
                this.Logger.WriteLine ("SKIPPING define statement: " + name);
                return null;
            }
            if (!signature.Contains ("(")) { // e.g. NS_DURING
                this.Logger.WriteLine ("SKIPPING non-function statement: " + name);
                return null;
            }

            // Trim down signature
            while (signature.IndexOf("  ") != -1) {
                signature = signature.Replace ("  ", " ");
            }
            while (signature.IndexOf(" (") != -1) {
                signature = signature.Replace (" (", "(");
            }
            functionEntity.Signature = signature;
            //Console.WriteLine("name='" + name + "' signature='" + signature + "'");

            // Parse signature
            int pos = signature.IndexOf (name + "(");
            if (pos == -1) {
                this.Logger.WriteLine ("MISMATCH between name and declaration: " + name);
                return null;
            }
            String returnType = signature.Substring (0, pos).Trim ();
            int paramsIndex = pos + name.Length;
            int paramsLength = signature.IndexOf(')') + 1 - paramsIndex; // Stop before getting to function body
            String parameters = signature.Substring (paramsIndex, paramsLength).Trim ();
            parameters = parameters.Trim (';', '(', ')').Trim();
            if (parameters != "void") {
                foreach (string parameter in parameters.Split(new []{','}, StringSplitOptions.RemoveEmptyEntries)) {
                    String parameterType = "NOTYPE";
                    String parameterName = "NONAME";

                    //Console.WriteLine("parameter='" + parameter + "'");
                    Match r = PARAMETER_REGEX.Match (parameter);
                    if (r.Success) {
                        parameterType = r.Groups [2].Value.Trim ();
                        parameterName = r.Groups [3].Value.Trim ();
                    } else if (parameter.Trim () == "...") {
                        parameterType = "params Object[]";
                        parameterName = "values";
                    } else {
                        this.Logger.WriteLine ("FAILED to parse parameter: " + parameter);
                        return null;
                    }
                    parameterType = parameterType.Trim ();

                    MethodParameterEntity parameterEntity = new MethodParameterEntity ();
                    bool isOut, isByRef, isBlock;
                    parameterEntity.Type = this.TypeManager.ConvertType (parameterType, out isOut, out isByRef, out isBlock, this.Logger);
                    parameterEntity.IsOut = isOut;
                    parameterEntity.IsByRef = isByRef;
                    parameterEntity.IsBlock = isBlock;
                    parameterEntity.Name = TypeManager.ConvertName(parameterName);
                    functionEntity.Parameters.Add (parameterEntity);
                }
            }

            // Extract return type
            functionEntity.ReturnType = this.TypeManager.ConvertType (returnType, this.Logger);

            // Extract parameter documentation
            if (functionEntity.Parameters.Count > 0) {
                XElement termList = (from el in functionElement.Elements ("div").Elements ("dl")
                                     where (String)el.Parent.Attribute ("class") == "api parameters"
                    && (String)el.Attribute ("class") == "termdef"
                                     select el).FirstOrDefault ();
                if (termList != null) {
                    IEnumerable<XElement> dtList = from el in termList.Elements ("dt") select el;
                    IEnumerable<XElement> ddList = from el in termList.Elements ("dd") select el;

                    if (dtList.Count () == ddList.Count ()) {
                        // Iterate over definitions
                        for (int i = 0; i < dtList.Count(); i++) {
                            String term = dtList.ElementAt (i).TrimAll ();
                            IEnumerable<String> summaries = ddList.ElementAt (i).Elements ("p").Select (p => p.Value.TrimAll ());

                            // Find the parameter
                            MethodParameterEntity parameterEntity = functionEntity.Parameters.Find (p => String.Equals (p.Name, term));
                            if (parameterEntity != null) {
                                foreach (string sum in summaries) {
                                    parameterEntity.Summary.Add (sum);
                                }
                            }
                        }
                    }
                }
            }

            // Fix the name only after looking for the documentation
            for (int i = 0; i < functionEntity.Parameters.Count; i++) {
                functionEntity.Parameters [i].Name = this.TypeManager.ConvertName (functionEntity.Parameters [i].Name);
            }

            // Get the summary for return type
            if (!String.Equals (functionEntity.ReturnType, "void", StringComparison.OrdinalIgnoreCase)) {
                XElement returnValueElement = (from el in functionElement.ElementsAfterSelf ("div")
                                               where (String)el.Attribute ("class") == "return_value"
                                               select el).FirstOrDefault ();
                if (returnValueElement != null) {
                    IEnumerable<String> documentations = returnValueElement.Elements ("p").Select (p => p.Value.TrimAll ());
                    functionEntity.ReturnsDocumentation = String.Join (String.Empty, documentations.ToArray ());
                }
            }

            //// Extract discussion
            //XElement discussionElement = (from el in functionElement.ElementsAfterSelf("div")
            //                              where (String) el.Attribute("class") == "api discussion"
            //                              select el).FirstOrDefault();
            //if (discussionElement != null)
            //{
            //    foreach (XElement paragraph in discussionElement.Elements("p"))
            //    {
            //        functionEntity.Summary.Add(paragraph.TrimAll());
            //    }
            //}

            // Get the availability
            XElement availabilityElement = (from el in functionElement.ElementsAfterSelf ("div")
                                            where (String)el.Attribute ("class") == "api availability"
                                            select el).FirstOrDefault ();
            XElement minAvailabilityElement = null;
            if (availabilityElement != null) {
                minAvailabilityElement = availabilityElement.Elements("ul").Elements("li").FirstOrDefault();
            }
            String minAvailability = "";
            if (minAvailabilityElement != null) {
                minAvailability = minAvailabilityElement.TrimAll();
            }
            functionEntity.MinAvailability = CommentHelper.ExtractAvailability (minAvailability);

            return functionEntity;
        }
 protected static XElement SetElementAndGetNext(XElement element, DataRow seat)
 {
     element.Attributes().Where(x => x.Name.LocalName == "class").Remove();
     element.SetAttributeValue("data-seat-row", seat["seat_row"].ToString().Trim());
     element.SetAttributeValue("data-seat-num", seat["seat_num"].ToString().Trim());
     //element.SetAttributeValue("data-seat-status", seat["seat_status"].ToString().Trim());
     element.SetAttributeValue("id", seat["seat_no"].ToString().Trim());
     //element.SetAttributeValue("data-zone", seat["zone_no"].ToString().Trim());
     return element.ElementsAfterSelf().FirstOrDefault();
 }
Esempio n. 16
0
                /// <summary>
                /// Tests the ElementsAfterSelf methods on Node.
                /// </summary>
                /// <param name="context"></param>
                /// <returns></returns>
                //[Variation(Desc = "NodeElementsAfterSelf")]
                public void NodeElementsAfterSelf()
                {
                    XElement parent = new XElement("parent");

                    XElement child1a = new XElement("child1", new XElement("nested"));
                    XElement child1b = new XElement("child1", new XElement("nested"));
                    XElement child2a = new XElement("child2", new XElement("nested"));
                    XElement child2b = new XElement("child2", new XElement("nested"));

                    XComment comment = new XComment("this is a comment");

                    // If no parent, should not be any elements before it.
                    Validate.Enumerator(comment.ElementsAfterSelf(), new XElement[0]);

                    parent.Add(child1a);
                    parent.Add(comment);
                    parent.Add(child1b);
                    parent.Add(child2a);
                    parent.Add(child2b);

                    Validate.Enumerator(
                        comment.ElementsAfterSelf(),
                        new XElement[] { child1b, child2a, child2b });

                    Validate.Enumerator(
                        comment.ElementsAfterSelf("child1"),
                        new XElement[] { child1b });

                    Validate.Enumerator(
                        child1a.ElementsAfterSelf("child1"),
                        new XElement[] { child1b });

                    Validate.Enumerator(child2b.ElementsAfterSelf(), new XElement[0]);
                }
        // Transform the w:p element, including the following sibling w:p element(s)
        // in case the w:p element has a style separator. The sibling(s) will be
        // transformed to h:span elements rather than h:p elements and added to
        // the element (e.g., h:h2) created from the w:p element having the (first)
        // style separator (i.e., a w:specVanish element).
        private static object ProcessParagraph(WordprocessingDocument wordDoc, HtmlConverterSettings settings,
            XElement element, bool suppressTrailingWhiteSpace, decimal currentMarginLeft)
        {
            // Ignore this paragraph if the previous paragraph has a style separator.
            // We have already transformed this one together with the previous one.
            var previousParagraph = element.ElementsBeforeSelf(W.p).LastOrDefault();
            if (HasStyleSeparator(previousParagraph)) return null;

            var elementName = GetParagraphElementName(element, wordDoc);
            var isBidi = IsBidi(element);
            var paragraph = (XElement) ConvertParagraph(wordDoc, settings, element, elementName,
                suppressTrailingWhiteSpace, currentMarginLeft, isBidi);

            // The paragraph conversion might have created empty spans.
            // These can and should be removed because empty spans are
            // invalid in HTML5.
            paragraph.Elements(Xhtml.span).Where(e => e.IsEmpty).Remove();

            while (HasStyleSeparator(element))
            {
                element = element.ElementsAfterSelf(W.p).FirstOrDefault();
                if (element == null) break;

                elementName = Xhtml.span;
                isBidi = IsBidi(element);
                var span = ConvertParagraph(wordDoc, settings, element, elementName,
                    suppressTrailingWhiteSpace, currentMarginLeft, isBidi);
                paragraph.Add(span);
            }

            return paragraph;
        }
 private IList<XElement> GetIdenticallyNamedSiblings(XElement element)
 {
     return element.ElementsBeforeSelf(element.Name).Union(element.ElementsAfterSelf(element.Name)).ToArray();
 }