Roslyn+T4+EnvDTE项目完全自动化(7) ——光标取元素(XPath)
(视频演示)
获取xml XPath
- 有些很复杂的xml 嵌套多个命名空间,手写 XPath 经常出错,想一步到位
按Alt+C调用GetXPath
- 生成代码(选择节点)
var namespaceManager = new XmlNamespaceManager(new NameTable()); namespaceManager.AddNamespace("x", "http://schemas.microsoft.com/ado/2009/11/edmx"); namespaceManager.AddNamespace("x1", "http://schemas.microsoft.com/ado/2009/11/edm/ssdl");
//带命名空间 var elements = doc.XPathSelectElements("/x:Edmx/x:Runtime/x:StorageModels/x1:Schema/x1:EntityContainer/x1:EntitySet", namespaceManager);
//不带命名空间
var elements1 = doc.XPathSelectElements("/Edmx/Runtime/StorageModels/Schema/EntityContainer/EntitySet", namespaceManager);
- 生成代码(选择属性)
var namespaceManager = new XmlNamespaceManager(new NameTable()); namespaceManager.AddNamespace("x", "http://schemas.microsoft.com/ado/2009/11/edmx"); namespaceManager.AddNamespace("x1", "http://schemas.microsoft.com/ado/2009/11/edm/ssdl"); namespaceManager.AddNamespace("x2", "http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator");
//带命名空间 var elements = doc.XPathSelectElements("/x:Edmx/x:Runtime/x:StorageModels/x1:Schema/x1:EntityContainer/x1:EntitySet", namespaceManager);
//不带命名空间 var elements1 = doc.XPathSelectElements("/Edmx/Runtime/StorageModels/Schema/EntityContainer/EntitySet", namespaceManager);
//不带命名空间XPath var elements2 = doc.XPathSelectElements("/x:Edmx/x:Runtime/x:StorageModels/x1:Schema/x1:EntityContainer/x1:EntitySet[@x2:Type='Tables']", namespaceManager); XNamespace ns = "http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator"; var attribute = elem.Attribute(ns + "Type");
- 怎么实现
- 用DTE获取光标的行、列号
- 行列转换成Roslyn的Microsoft.CodeAnalysis.Text.TextSpan span
- 设置xml解析保留行号:XDocument.Parse(text, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
- 判断xml节点与span相交的元素
- 核心代码
public void FindElem() { var span = dte.GetTextSpanner(ProjectItem.GetFileName()).GetDteTextSpan(); foreach (var element in Document.Descendants()) { { var lineInfo = (IXmlLineInfo)element; if (!lineInfo.HasLineInfo()) { continue; } var r = GetLineInfos(element); if (span.iStartLine <= r.End && span.iEndLine >= r.Start) { var name = element.GetNameWithPrefix(); if (span.iEndLine > span.iStartLine || span.iStartIndex >= lineInfo.LinePosition && span.iStartIndex <= lineInfo.LinePosition + name.Length) { Elem = element; } } } foreach (var attribute in element.Attributes()) { var lineInfo = (IXmlLineInfo)attribute; if (!lineInfo.HasLineInfo()) continue; if (lineInfo.LineNumber >= span.iStartLine && lineInfo.LineNumber <= span.iEndLine) { var name = attribute.ToString(); var yStart = lineInfo.LinePosition; var yEnd = yStart + name.Length - 1; if (span.iStartLine != span.iEndLine || span.iStartIndex <= yEnd && span.iEndIndex >= yStart) { Elem = element; Attributes.Add(attribute); } } } if (Elem != null) { goto Return; } } throw new Exception("not find XElement"); Return: var items = new List() { Elem, }; foreach (var element in Elem.ElementsAfterSelf()) { var lineInfo = (IXmlLineInfo)element; if (!lineInfo.HasLineInfo()) continue; if (lineInfo.LineNumber < span.iEndLine) { items.Add(element); } else if (lineInfo.LineNumber == span.iEndLine) { if (span.iEndIndex >= lineInfo.LinePosition) { items.Add(element); } } } Elems = items; }