• 【Visual Studio2010】创建XAML分析插件


    最近项目[Silverlight]中的需要实现国际化,需要对所有控件进行一个处理。由于使用了Telerik的控件,只需要去掉原有的Label或者Header属性,然后添加一个资源Key即可。但是在项目已经完全成熟的情况下,对大量的查询条件,数据列进行处理也是一个非常耗时的方案,因此对XAML文件进行处理能够节省大量的工作量,避免错误信息。

     关键的步骤可以通过VS的向导自动完成。接下来只需在Conect.cs文件中对部分数据进行处理。

        /// <summary>实现 IDTCommandTarget 接口的 Exec 方法。此方法在调用该命令时调用。</summary>
        /// <param term='commandName'>要执行的命令的名称。</param>
        /// <param term='executeOption'>描述该命令应如何运行。</param>
        /// <param term='varIn'>从调用方传递到命令处理程序的参数。</param>
        /// <param term='varOut'>从命令处理程序传递到调用方的参数。</param>
        /// <param term='handled'>通知调用方此命令是否已被处理。</param>
        /// <seealso class='Exec' />
            public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
            {
                handled = false;
                if (executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
                {
                    if (_applicationObject.ActiveDocument == null)
                        return;
                    // 获取当前画面名称
                    string pageName = _applicationObject.ActiveDocument.Name;
                    pageName = pageName.Substring(0, pageName.IndexOf("."));
    
                    TextDocument doc = _applicationObject.ActiveDocument.Object() as TextDocument;
                    if (commandName == "Aladdin.Connect.Aladdin")
                    {
                        try
                        {
                            // 获取当前的内容,并进行替换
                            var startPoint = doc.CreateEditPoint(doc.StartPoint);
                            var text = startPoint.GetText(doc.EndPoint);
                            string newContent = I18nHelper.DoReplace(pageName, text);
                            // 先删除
                            startPoint.Delete(doc.EndPoint);
                            // 重新写入
                            startPoint.Insert(newContent);
    
                            handled = true;
                            return;
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show("格式化错误。" + ex.Message);
                        }
                    }
                }
            }

    主要代码就是通过获取当前的TextDocument进行处理。

    在编辑器文档中中获取一段内容的方法就是定义一个起始位置,然后从起始位置开始通过GetText获取到指定结束位置。

    然后通过Delete和Insert进行处理。 

    NOTE:之前尝试了使用SelectionText进行处理,发现替换效率比较慢,应该是SelectionText这个对象是内容更新时一直在变化的原因。 

    对文本进行分析有多种办法,比如正则表达式、字符串查找替换等,这里由于处理的是XAML,因此使用了XML的处理方式。

    在分析之前有几点需要注意的地方:

    • XAML是带有命名空间的,需要预先分析命名空间,并在带有命名空间的SelectNodes等地方使用;
    • 在添加(或者修改,此处有待确认)节点或者属性时,需要注意
    • XML内容在输出为字符串,并将内容传给编辑器时,需要使用XmlWriterSettings进行处理缩进等问题。
            public static string DoReplace(string pageName, string content)
            {
                if (String.IsNullOrEmpty(content)) return content;
    
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(content);
    
                XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable);
                var docRoot = doc.FirstChild;
    
                // 根据根节点信息,获取命名空间列表
                foreach (var ns in GetNamespaces(docRoot))
                    nsManager.AddNamespace(ns.Key, ns.Value);
    
                // 遍历所有子节点,进行处理
                foreach (XmlNode root in docRoot.ChildNodes)
                {
                    Process(doc, root, pageName, nsManager);
                }
    
                // 数据输出,格式设定
                StringBuilder strBuilder = new StringBuilder();
                XmlWriterSettings settings = new XmlWriterSettings();
                settings.Indent = true;
                settings.NewLineHandling = NewLineHandling.Replace;
                settings.OmitXmlDeclaration = true;
                settings.ConformanceLevel = ConformanceLevel.Fragment;
    
                XmlWriter writer = XmlWriter.Create(strBuilder, settings);
                doc.WriteTo(writer);
                writer.Flush();
                writer.Close();
    
                // 替换根节点内容
                string newRootAttributes = ReplaceHelper.ProcessRoot(docRoot);
                string newContent = strBuilder.ToString();
    
                string newRawAttributes = newContent.Substring(0, newContent.IndexOf(">"));
                return newContent.Replace(newRawAttributes, newRootAttributes);
            }
    
    
            private static void Process(XmlDocument doc, XmlNode root, string pageName, XmlNamespaceManager nsManager)
            {
                // TODO:节点处理和递归
            }

    简单的添加属性的方法类似于,即必须制定其NamespaceURI,否则会自动在结点后添加命名空间属性:

     foreach (XmlNode field in root.SelectNodes("EF:EFDataFieldGroup.DataFields", nsManager))
                        {
                            if (field.Attributes == null) continue;
    
                            if (field.Attributes["EF:I18nManager.ResourceKey"] == null)
                            {
                                string fieldValue = field.OuterXml;
                                // 数据进行处理
                                var startIdx = fieldValue.IndexOf("inqu_status-0-");
                                var endIdx = fieldValue.IndexOf(""", startIdx);
    
                                if (startIdx + 14 >= endIdx) continue;
    
                                string itemId = fieldValue.Substring(startIdx + 14, endIdx - startIdx - 14);
                                string bindingName = string.Format("{0}U_DATAFIELD_{1}", pageName, itemId);
    
                                //XmlAttribute attr = doc.CreateAttribute("EF:I18nManager.ResourceKey", bindingName);
                                //field.Attributes.Append(attr);
    
                                //XmlElement element = field as XmlElement;
                                var attr = doc.CreateAttribute("EF:I18nManager.ResourceKey", field.NamespaceURI);
                                attr.Value = bindingName;
                                field.Attributes.Append(attr);
    
                                // 同时删除原有的标签
                                var labelAttr = field.Attributes["eLabel"];
                                if (null != labelAttr)
                                    field.Attributes.Remove(labelAttr);
                                //element.SetAttribute("EF:I18nManager.ResourceKey",field.NamespaceURI, bindingName);
                            }
                }
    View Code

    分析XAML文档的命名空间列表的简单实现如下:

            private static IDictionary<string, string> GetNamespaces(XmlNode root)
            {
                IDictionary<string, string> dicNS = new Dictionary<string, string>();
    
                // 获取第一个节点中的所有
    
                foreach (XmlNode node in root.Attributes)
                {
                    var item = node.OuterXml;
    
                    if (item.IndexOf("xmlns") > -1)
                    {
                        int nameStart = item.IndexOf(":");
                        int nameEnd = item.IndexOf("=");
                        if (nameStart >= nameEnd) continue;
    
                        string key = item.Substring(nameStart + 1, nameEnd - nameStart - 1).Trim();
    
                        if (String.IsNullOrEmpty(key)) continue;
    
                        int contentStart = item.IndexOf(""", nameEnd);
                        int contentEnd = item.IndexOf(""", contentStart + 1);
                        string val = item.Substring(contentStart + 1, contentEnd - 1 - contentStart);
    
                        dicNS.Add(key, val);
                    }
                }
    
                return dicNS;
            }
        }
  • 相关阅读:
    链家网各城市二手房价格
    mitmproxy 配置
    Python操作APP -- Appium-Python-Client
    Appium连接模拟器
    adb server version (xx) doesn't match this client (xx); killing...
    Appnium 环境搭建
    KeyError: 'xxx does not support field: _id'
    Python执行JS -- PyExecJS库
    Python -- CSV文件读写
    Git的基本使用 -- 分支管理
  • 原文地址:https://www.cnblogs.com/tukzer/p/3320948.html
Copyright © 2020-2023  润新知