Outling support for Xml

SyntaxEditor for Windows Forms Forum

Posted 19 years ago by Devin Grant - Novi
Avatar
Are there any plans to support outlining for Xml (i.e. VS2005 & XmlSpy 2005)?

I also noticed that C# comments outlined but VB.Net are not (i.e. '''<code>). How you are able to outline C # comments in the language file, can I do the same for VB.Net?

Comments (5)

Posted 19 years ago by Ashton - Developer, Schema Solutions LLC
Avatar
Devin,

I outline my own XML using the following code. It works fairly good in providing outlining support much like IE does in it's default XSL template for opened XML docs:
using System;
using System.Collections;
using System.Diagnostics;
using ActiproSoftware.SyntaxEditor;

namespace msSQLed {

    /// <summary>
    /// Provides an implementation of a HTML language semantic parser that can perform automatic outlining.
    /// </summary>
    public class SemanticXmlParser : SemanticDefaultParser {

        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // OBJECT
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Initializes a new instance of the <c>SemanticHtmlParser</c> class. 
        /// </summary>
        /// <remarks>
        /// The default constructor initializes all fields to their default values.
        /// </remarks>
        public SemanticXmlParser() {
        }

        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Gets a <see cref="ActiproSoftware.SyntaxEditor.AutomaticOutliningSupportType"/> that indicates the automatic outlining support.
        /// </summary>
        /// <value>A <see cref="ActiproSoftware.SyntaxEditor.AutomaticOutliningSupportType"/> that indicates the automatic outlining support.</value>
        public override AutomaticOutliningSupportType AutomaticOutliningSupportType { 
            get {
                return AutomaticOutliningSupportType.All;
            }
        }

        /// <summary>
        /// Returns token parsing information for automatic outlining that determines if the current <see cref="Token"/>
        /// in the <see cref="TokenStream"/> starts or ends an outlining node.
        /// </summary>
        /// <param name="tokenStream">A <see cref="TokenStream"/> that is positioned at the <see cref="Token"/> requiring outlining data.</param>
        /// <param name="outliningKey">Returns the outlining node key to assign.  A <see langword="null"/> should be returned if the token doesn't start or end a node.</param>
        /// <param name="tokenAction">Returns the <see cref="OutliningNodeAction"/> to take for the token.</param>
        public override void GetTokenOutliningAction(TokenStream tokenStream, ref string outliningKey, ref OutliningNodeAction tokenAction) {
            // Get the token
            Token token = tokenStream.Peek();
            string languageTokenKey = token.Key;
            TokenCollection objTokens = tokenStream.Document.Tokens;
            int nStart = objTokens.IndexOf(token.StartOffset);
            Document doc = tokenStream.Document;

            // See if the token starts or ends an outlining node
            switch (languageTokenKey) {
                case "StartTagStartToken" :
                    // search forward and see if we have a newline before we get to either one of the possible ends
                    // if so, then make this a start outlining token
                    for (int nIndex = nStart + 1; nIndex < objTokens.Count; nIndex++)
                    {
                        // if we hit either of the ends, then return
                        switch (objTokens[nIndex].Key)
                        {
                            case "StartTagStartToken" :
                            case "EndTagStartToken" :
                                return;    
                            case "StartTagEndToken" :
                                if (doc.GetTokenText(objTokens[nIndex]) == "/>")
                                    return;
                                break;
                            default:
                                // if we hit a newline, then add this as the beginning of a outline region
                                if (doc.GetTokenText(objTokens[nIndex]) != null && doc.GetTokenText(objTokens[nIndex]) == "\n")
                                {
                                    outliningKey = "StartTag";
                                    tokenAction = OutliningNodeAction.Start;
                                }
                                break;
                        }
                    }
                    break;
                case "EndTagEndToken" :
                    // search backwards in document and make sure that there was a newline
                    // before the start of this element
                    for (int nIndex = nStart - 1; nIndex >= 0; nIndex--)
                    {
                        // if we hit either of the ends, then return
                        switch (objTokens[nIndex].Key)
                        {
                            case "StartTagStartToken" :
                                return;                            
                            default:
                                // if we hit a newline, then add this as the beginning of a outline region
                                if (doc.GetTokenText(objTokens[nIndex]) != null && doc.GetTokenText(objTokens[nIndex]) == "\n")
                                {
                                    outliningKey = "StartTag";
                                    tokenAction = OutliningNodeAction.End;
                                }
                                break;
                        }
                    }
                    break;

            }
        }

        /// <summary>
        /// Allows for setting the collapsed text for the specified <see cref="OutliningNode"/>.
        /// </summary>
        /// <param name="node">The <see cref="OutliningNode"/> that is requesting collapsed text.</param>
        public override void SetOutliningNodeCollapsedText(OutliningNode node) {
            Token objToken = node.Document.Tokens[node.Document.Tokens.IndexOf(node.StartOffset) + 1];

            switch (node.ParseData.Key) {
                case "StartTag":
                    node.CollapsedText = node.Document.GetTokenText(objToken) + "...";
                    break;
            }
        }

    }
}
[Modified at 06/02/2005 05:57 AM]
Posted 19 years ago by Boyd - Sr. Software Developer, Patterson Consulting, LLC
Avatar
Thanks for posting that Asthon. That code works perfectly.
Posted 19 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Thanks for posting that Ashton. I hope you don't mind but I edited your message to add the C# syntax highlighting to it.

We are currently working on developing a way to do advanced parsing for specific languages. Something that is integrated in this is outlining. So our goal is to have outlining for the most common languages like XML and others.

In the meantime your code should work great.

For the VB.NET comments you can implement the same sort of thing that we did in our C# sample language for comments there. It should be easy to translate over.


Actipro Software Support

Posted 19 years ago by Devin Grant - Novi
Avatar
The code above doesn't work for all cases. The example listed below displays outline for "<item/>" when "/>" is on a separate line.

<parent>
    <item node="">
        <item
            name=""
        />
    </item>
</parent>
Posted 19 years ago by Devin Grant - Novi
Avatar
Here is an alternative way to get outling for Xml
public override void GetTokenOutliningAction(TokenStream tokenStream, ref string outliningKey, ref OutliningNodeAction tokenAction)
{
    Token token = tokenStream.Peek();
    TokenCollection objTokens = tokenStream.Document.Tokens;
    int nStart = objTokens.IndexOf(token.StartOffset);
    Document doc = tokenStream.Document;
    bool isEndTag = false;
    bool isStartTag = false;
    Token prevToken = null;

    if (tokenStream.Position > 1)
        prevToken = tokenStream.PeekReverse();

    if (prevToken != null && prevToken.Key == "StartTagEndToken" && doc.GetTokenText(prevToken) == ">")
    {
        // search forward and see if we have a newline before we get to either one of the possible ends
        // if so, then make this a start outlining token
        for (int nIndex = nStart; nIndex < objTokens.Count; nIndex++)
        {
            string text = doc.GetTokenText(objTokens[nIndex]);

            if (text == ">")
            {
                isEndTag = true;
            }
            else if (text == "/")
            {
                break;
            }
            else if (isEndTag)
            {
                tokenAction = OutliningNodeAction.Start;
                break;
            }
        }
    }

    if (token.Key == "EndTagEndToken" && doc.GetTokenText(token) == ">")
    {
        // search backwards in document and make sure that there was a newline
        // before the start of this element
        for (int nIndex = nStart - 1; nIndex >= 0; nIndex--)
        {
            string text = doc.GetTokenText(objTokens[nIndex]);

            if (text == "</")
            {
                isStartTag = true;
            }
            else if (isStartTag)
            {
                tokenAction = OutliningNodeAction.End;
                break;
            }
        }
    }
}
[Modified at 06/02/2005 02:31 PM]
The latest build of this product (v24.1.0) was released 2 months ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.