コード例 #1
0
        /// <summary>
        ///     Inspect the specified location in the XML.
        /// </summary>
        /// <param name="position">
        ///     The location's position.
        /// </param>
        /// <returns>
        ///     An <see cref="XmlLocation"/> representing the result of the inspection.
        /// </returns>
        public XmlLocation Inspect(Position position)
        {
            // Internally, we always use 1-based indexing because this is what the System.Xml APIs (and I'd rather keep things simple).
            position = position.ToOneBased();

            XSNode nodeAtPosition = FindNode(position);

            if (nodeAtPosition == null)
            {
                return(null);
            }

            // If we're on the (seamless, i.e. overlapping) boundary between 2 nodes, select the next node.
            if (nodeAtPosition.NextSibling != null)
            {
                if (position == nodeAtPosition.Range.End && position == nodeAtPosition.NextSibling.Range.Start)
                {
                    Serilog.Log.Debug("XmlLocator.Inspect moves to next sibling ({NodeKind} @ {NodeRange} -> {NextSiblingKind} @ {NextSiblingRange}).",
                                      nodeAtPosition.Kind,
                                      nodeAtPosition.Range,
                                      nodeAtPosition.NextSibling.Kind,
                                      nodeAtPosition.NextSibling.Range
                                      );

                    nodeAtPosition = nodeAtPosition.NextSibling;
                }
            }

            int absolutePosition = _documentPositions.GetAbsolutePosition(position);

            XmlLocationFlags flags            = ComputeLocationFlags(nodeAtPosition, absolutePosition);
            XmlLocation      inspectionResult = new XmlLocation(position, absolutePosition, nodeAtPosition, flags);

            return(inspectionResult);
        }
コード例 #2
0
        /// <summary>
        ///     Create a new <see cref="XmlLocation"/>.
        /// </summary>
        /// <param name="position">
        ///     The location's position, in line / column form.
        /// </param>
        /// <param name="absolutePosition">
        ///     The location's (0-based) absolute position.
        /// </param>
        /// <param name="node">
        ///     The <see cref="XSNode"/> closest to the location's position.
        /// </param>
        /// <param name="flags">
        ///     <see cref="XmlLocationFlags"/> describing the location.
        /// </param>
        public XmlLocation(Position position, int absolutePosition, XSNode node, XmlLocationFlags flags)
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            Position         = position;
            AbsolutePosition = absolutePosition;
            Node             = node;
            Flags            = flags;
        }
コード例 #3
0
        /// <summary>
        ///     Determine <see cref="XmlLocationFlags"/> for the current position.
        /// </summary>
        /// <returns>
        ///     <see cref="XmlLocationFlags"/> describing the position.
        /// </returns>
        XmlLocationFlags ComputeLocationFlags(XSNode node, int absolutePosition)
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            XmlLocationFlags flags = XmlLocationFlags.None;

            if (!node.IsValid)
            {
                flags |= XmlLocationFlags.Invalid;
            }

            switch (node)
            {
            case XSEmptyElement element:
            {
                flags |= XmlLocationFlags.Element | XmlLocationFlags.Empty;

                XmlEmptyElementSyntax syntaxNode = element.ElementNode;

                TextSpan nameSpan = syntaxNode.NameNode?.Span ?? new TextSpan();
                if (nameSpan.Contains(absolutePosition))
                {
                    flags |= XmlLocationFlags.Name;
                }

                TextSpan attributesSpan = new TextSpan();
                if (syntaxNode.SlashGreaterThanToken != null)     // This is the most accurate way to measure the span of text where the element's attributes can be located.
                {
                    attributesSpan = new TextSpan(start: syntaxNode.NameNode.Span.End, length: syntaxNode.SlashGreaterThanToken.Span.Start - syntaxNode.NameNode.Span.End);
                }
                else if (syntaxNode.AttributesNode != null)
                {
                    attributesSpan = syntaxNode.AttributesNode.FullSpan;     // We don't rely on the span of the syntaxNode.AttributesNode unless we have to, because it's often less accurate than the measurement above.
                }
                if (attributesSpan.Contains(absolutePosition))
                {
                    flags |= XmlLocationFlags.Attributes;
                }

                break;
            }

            case XSElementWithContent elementWithContent:
            {
                flags |= XmlLocationFlags.Element;

                XmlElementSyntax syntaxNode = elementWithContent.ElementNode;

                TextSpan nameSpan = syntaxNode.NameNode?.Span ?? new TextSpan();
                if (nameSpan.Contains(absolutePosition))
                {
                    flags |= XmlLocationFlags.Name;
                }

                TextSpan startTagSpan = syntaxNode.StartTag?.Span ?? new TextSpan();
                if (startTagSpan.Contains(absolutePosition))
                {
                    flags |= XmlLocationFlags.OpeningTag;
                }

                TextSpan attributesSpan = new TextSpan();
                if (syntaxNode.StartTag?.GreaterThanToken != null)     // This is the most accurate way to measure the span of text where the element's attributes can be located.
                {
                    attributesSpan = new TextSpan(start: syntaxNode.NameNode.Span.End, length: syntaxNode.StartTag.GreaterThanToken.Span.Start - syntaxNode.NameNode.Span.End);
                }
                else if (syntaxNode.AttributesNode != null)
                {
                    attributesSpan = syntaxNode.AttributesNode.FullSpan;                                 // We don't rely on the span of the syntaxNode.AttributesNode unless we have to, because it's often less accurate than the measurement above.
                }
                if (attributesSpan.Contains(absolutePosition) || absolutePosition == attributesSpan.End) // In this particular case, we need an inclusive comparison.
                {
                    flags |= XmlLocationFlags.Attributes;
                }

                TextSpan endTagSpan = syntaxNode.EndTag?.Span ?? new TextSpan();
                if (endTagSpan.Contains(absolutePosition))
                {
                    flags |= XmlLocationFlags.ClosingTag;
                }

                if (absolutePosition >= startTagSpan.End && absolutePosition <= endTagSpan.Start)
                {
                    flags |= XmlLocationFlags.Value;
                }

                break;
            }

            case XSInvalidElement invalidElement:
            {
                flags |= XmlLocationFlags.Element;

                XmlElementSyntaxBase syntaxNode = invalidElement.ElementNode;

                TextSpan nameSpan = syntaxNode.NameNode?.Span ?? new TextSpan();
                if (nameSpan.Contains(absolutePosition))
                {
                    flags |= XmlLocationFlags.Name;
                }

                TextSpan attributesSpan = syntaxNode.AttributesNode?.FullSpan ?? new TextSpan();
                if (attributesSpan.Contains(absolutePosition))
                {
                    flags |= XmlLocationFlags.Attributes;
                }

                break;
            }

            case XSAttribute attribute:
            {
                flags |= XmlLocationFlags.Attribute;

                XmlAttributeSyntax syntaxNode = attribute.AttributeNode;

                TextSpan nameSpan = syntaxNode.NameNode?.Span ?? new TextSpan();
                if (nameSpan.Contains(absolutePosition))
                {
                    flags |= XmlLocationFlags.Name;
                }

                TextSpan valueSpan = syntaxNode.ValueNode?.Span ?? new TextSpan();
                if (absolutePosition >= valueSpan.Start + 1 && absolutePosition <= valueSpan.End - 1)
                {
                    flags |= XmlLocationFlags.Value;
                }

                break;
            }

            case XSElementText text:
            {
                flags |= XmlLocationFlags.Text | XmlLocationFlags.Element | XmlLocationFlags.Value;

                break;
            }

            case XSWhitespace whitespace:
            {
                flags |= XmlLocationFlags.Whitespace | XmlLocationFlags.Element | XmlLocationFlags.Value;

                break;
            }
            }

            return(flags);
        }