/// <summary> /// 根据筛选路径值匹配HTML节点集合 /// </summary> /// <param name="path">筛选路径</param> /// <param name="node">筛选节点</param> /// <returns>匹配的HTML节点集合</returns> public static list<htmlNode> Get(string path, htmlNode node) { if (path != null && path.Length != 0) { list<htmlNode> nodes = new list<htmlNode>(); nodes.Add(node); return get(path).get(new keyValue<list<htmlNode>, bool>(nodes, false)); } return null; }
/// <summary> /// 预定义生成 /// </summary> /// <param name="parameter">安装参数</param> public static void Setup(auto.parameter parameter) { try { string csproj = parameter.ProjectPath + "fastCSharp.csproj"; if (File.Exists(csproj)) { list<htmlNode> nodes = new htmlNode(File.ReadAllText(csproj)).Path(@"TargetFrameworkVersion"); if (nodes != null) { string define = null; foreach (htmlNode node in nodes) { string version = nodes[0].Text.Trim(); if (version.Length > 1 && version[0] == 'v') { int leftVersion, dotIndex = version.IndexOf('.'); if (int.TryParse(dotIndex != -1 ? version.Substring(1, dotIndex - 1) : version.Substring(1), out leftVersion)) { define = @" "; if (leftVersion == 3 ? dotIndex != -1 && ++dotIndex != version.Length && version[dotIndex] >= '5' : leftVersion > 3) { define = @" #define DOTNET35 "; } break; } } error.Add("不可识别的 TargetFrameworkVersion : " + version); } if (define != null) { foreach (string file in Directory.GetFiles(parameter.ProjectPath, "*.cs", SearchOption.AllDirectories)) { if (file.IndexOf('@') == -1) { string code = File.ReadAllText(file); if (code.StartsWith(defineStart, StringComparison.Ordinal) && !new subString(code, defineStart.Length).StartsWith(define + defineEnd)) { int endIndex = code.IndexOf(defineEnd); if (endIndex != -1) { cSharp.coder.MoveFile(file, defineStart + define + defineEnd + code.Substring(endIndex + defineEnd.Length)); } else error.Add(file + " 没有找到结束符 " + defineEnd); } } } return; } } error.Add("没有找到 TargetFrameworkVersion"); } else error.Add("没有找到项目文件"); } catch (Exception error) { setup.error.Add(error); } finally { error.Open(true); } }
/// <summary> /// 替换子节点 /// </summary> /// <param name="oldNode">待替换的子节点</param> /// <param name="newNode">新的子节点</param> /// <returns>是否存在待替换的子节点</returns> public bool ReplaceChild(htmlNode oldNode, htmlNode newNode) { bool isReplace = false; if (oldNode != null && newNode != null) { int oldIndex = this[oldNode]; if (oldIndex != -1) { if (newNode.TagName == string.Empty) { oldNode.Parent = null; if (newNode.children == null) children.RemoveAt(oldIndex); else { foreach (htmlNode value in newNode.children) value.Parent = this; if (newNode.children.Count == 1) children[oldIndex] = newNode.children[0]; else if (oldIndex == children.Count - 1) { children.RemoveAt(oldIndex); children.Add(newNode.children); } else { list<htmlNode>.unsafer values = new list<htmlNode>(children.Count + newNode.children.Count).Unsafer; int newIndex = 0; while (newIndex != oldIndex) values.Add(children[newIndex++]); values.List.Add(newNode.children); for (oldIndex = children.Count; ++newIndex != oldIndex; values.Add(children[newIndex])) ; children = values.List; } } newNode.children = null; isReplace = true; } else if (!newNode.IsNode(this)) { int newIndex = this[newNode]; if (newIndex == -1) { if (newNode.Parent != null) newNode.Parent.RemoveChild(newNode); newNode.Parent = this; children[oldIndex] = newNode; oldNode.Parent = null; } else { children[oldIndex] = newNode; oldNode.Parent = null; children.RemoveAt(newIndex); } isReplace = true; } } } return isReplace; }
/// <summary> /// 解析HTML节点 /// </summary> /// <param name="html"></param> private void create(string html) { int length = html.Length; children = new list<htmlNode>(); if (length < 2) { children.Add(new htmlNode { nodeText = new htmlText { FormatHtml = html }, Parent = this }); } else { int nextIndex, nodeCount; htmlNode nextNode; fixed (char* htmlFixed = html + "<") { fixedMap spaceFixedMap = new fixedMap(spaceMap.Map); fixedMap spaceSplitFixedMap = new fixedMap(spaceSplitMap); fixedMap tagNameFixedMap = new fixedMap(tagNameMap); fixedMap tagNameSplitFixedMap = new fixedMap(tagNameSplitMap); fixedMap attributeSplitFixedMap = new fixedMap(attributeSplitMap); fixedMap attributeNameSplitFixedMap = new fixedMap(attributeNameSplitMap); int startIndex, tagNameLength; string name, htmlValue; char* startChar = htmlFixed, currentChar = htmlFixed, endChar = htmlFixed + length, scriptChar; char splitChar; while (currentChar != endChar) { for (*endChar = '<'; *currentChar != '<'; ++currentChar) ; if (currentChar != endChar) { if ((*++currentChar & 0xff80) == 0) { if (tagNameFixedMap.Get(*currentChar)) { while ((*startChar & 0xffc0) == 0 && spaceFixedMap.Get(*startChar)) ++startChar; if (startChar != currentChar - 1) { for (scriptChar = currentChar - 2; (*scriptChar & 0xffc0) == 0 && spaceFixedMap.Get(*scriptChar); --scriptChar) ; children.Add(new htmlNode { nodeText = new htmlText { FormatHtml = html.Substring((int)(startChar - htmlFixed), (int)(scriptChar - startChar) + 1) } }); } if (*currentChar == '/') { #region 标签回合 startChar = currentChar - 1; if (++currentChar != endChar) { while ((*currentChar & 0xffc0) == 0 && spaceFixedMap.Get(*currentChar)) ++currentChar; if (currentChar != endChar) { if ((uint)((*currentChar | 0x20) - 'a') <= 26) { for (*endChar = '>'; (*currentChar & 0xffc0) != 0 || !tagNameSplitFixedMap.Get(*currentChar); ++currentChar) ; TagName = html.Substring((int)((startChar += 2) - htmlFixed), (int)(currentChar - startChar)).toLower(); for (startIndex = children.Count - 1; startIndex >= 0 && (children[startIndex].nodeText.FormatHtml != null || children[startIndex].TagName != TagName); --startIndex) ; if (startIndex != -1) { for (nextIndex = children.Count - 1; nextIndex != startIndex; --nextIndex) { nextNode = children[nextIndex]; if (nextNode.nodeText.FormatHtml == null) { if (web.html.MustRoundTagNames.Contains(nextNode.TagName) && (nodeCount = (children.Count - nextIndex - 1)) != 0) { nextNode.children = new list<htmlNode>(children.GetSub(nextIndex + 1, nodeCount), true); children.RemoveRange(nextIndex + 1, nodeCount); foreach (htmlNode value in nextNode.children) value.Parent = nextNode; } } else if (nextNode.nodeText.FormatHtml.Length == 0) nextNode.nodeText.FormatHtml = null; } nextNode = children[startIndex]; if ((nodeCount = children.Count - ++startIndex) != 0) { nextNode.children = new list<htmlNode>(children.GetSub(startIndex, nodeCount), true); children.RemoveRange(startIndex, nodeCount); foreach (htmlNode value in nextNode.children) value.Parent = nextNode; } nextNode.nodeText.FormatHtml = string.Empty;//已回合标识 } while (*currentChar != '>') ++currentChar; if (currentChar != endChar) ++currentChar; } else { for (*endChar = '>'; *currentChar != '>'; ++currentChar) ; if (currentChar != endChar) ++currentChar; htmlValue = html.Substring((int)(startChar - htmlFixed), (int)(currentChar - startChar)); children.Add(new htmlNode { TagName = "/", nodeText = new htmlText { FormatHtml = htmlValue, FormatText = htmlValue } }); } startChar = currentChar; } } #endregion } else if (*currentChar != '!') { #region 标签开始 startChar = currentChar; children.Add(nextNode = new htmlNode()); for (*endChar = '>'; (*currentChar & 0xffc0) != 0 || !tagNameSplitFixedMap.Get(*currentChar); ++currentChar) ; nextNode.TagName = html.Substring((int)(startChar - htmlFixed), (int)(currentChar - startChar)).toLower(); if (currentChar == endChar) startChar = endChar; else { #region 属性解析 if (*currentChar != '>') { startChar = ++currentChar; while (currentChar != endChar) { while ((*currentChar & 0xffc0) == 0 && attributeSplitFixedMap.Get(*currentChar)) ++currentChar; if (*currentChar == '>') { if (currentChar != endChar) { if (*(currentChar - 1) == '/') nextNode.nodeText.FormatHtml = string.Empty; startChar = ++currentChar; } break; } else { for (startChar = currentChar++; (*currentChar & 0xffc0) != 0 || !tagNameSplitFixedMap.Get(*currentChar); ++currentChar) ; htmlValue = name = checkName(html.Substring((int)(startChar - htmlFixed), (int)(currentChar - startChar)).toLower()); if (currentChar != endChar && ((*currentChar & 0xffc0) != 0 || !attributeNameSplitFixedMap.Get(*currentChar))) { if (*currentChar != '=') { while ((*currentChar & 0xffc0) == 0 && spaceFixedMap.Get(*currentChar)) ++currentChar; } if (*currentChar == '=') { while ((*++currentChar & 0xffc0) == 0 && spaceFixedMap.Get(*currentChar)) ; if ((splitChar = *currentChar) != '>') { if (splitChar == '"' || splitChar == '\'') { for (startChar = ++currentChar, *endChar = splitChar; *currentChar != splitChar; ++currentChar) ; *endChar = '>'; } else { for (startChar = currentChar++; (*currentChar & 0xffc0) != 0 || !spaceSplitFixedMap.Get(*currentChar); ++currentChar) ; } htmlValue = html.Substring((int)(startChar - htmlFixed), (int)(currentChar - startChar)); } } } if (nextNode.attributes == null) nextNode.attributes = new Dictionary<string, htmlText>(); nextNode.attributes[name] = new htmlText { FormatHtml = htmlValue }; if (currentChar != endChar) { if (*currentChar == '>') { if (*(currentChar - 1) == '/') nextNode.nodeText.FormatHtml = string.Empty; startChar = ++currentChar; break; } startChar = ++currentChar; } } } } else startChar = ++currentChar; #endregion #region 非解析标签 if (currentChar == endChar) startChar = endChar; else if (web.html.NonanalyticTagNames.Contains(TagName = nextNode.TagName)) { scriptChar = endChar; tagNameLength = TagName.Length + 2; fixed (char* tagNameFixed = TagName) { while ((int)(endChar - currentChar) > tagNameLength) { for (currentChar += tagNameLength; *currentChar != '>'; ++currentChar) ; if (currentChar != endChar && *(int*)(currentChar - tagNameLength) == (('/' << 16) + '<')) { if (unsafer.String.EqualCase(currentChar - TagName.Length, tagNameFixed, TagName.Length)) { scriptChar = currentChar - tagNameLength; if (currentChar != endChar) ++currentChar; break; } } } } if (startChar != scriptChar) { nextNode.nodeText.FormatHtml = nextNode.nodeText.FormatText = html.Substring((int)(startChar - htmlFixed), (int)(scriptChar - startChar)); } if (scriptChar == endChar) currentChar = endChar; startChar = currentChar; } #endregion } #endregion } else { #region 注释 startChar = currentChar - 1; if (++currentChar != endChar) { *endChar = '>'; if ((length = (int)(endChar - currentChar)) > 2 && *(int*)currentChar == (('-' << 16) + '-')) { for (currentChar += 2; *currentChar != '>'; ++currentChar) ; while (currentChar != endChar && *(int*)(currentChar - 2) != (('-' << 16) + '-')) { if ((currentChar += 3) < endChar) { while (*currentChar != '>') ++currentChar; } else currentChar = endChar; } } else if (length > 9 && (*(int*)currentChar & 0x200000) == ('[' + ('c' << 16)) && (*(int*)(currentChar + 2) & 0x200020) == ('d' + ('a' << 16)) && (*(int*)(currentChar + 4) & 0x200020) == ('t' + ('a' << 16)) && *(currentChar + 6) == '[') { for (currentChar += 9; *currentChar != '>'; ++currentChar) ; while (currentChar != endChar && *(int*)(currentChar - 2) != ((']' << 16) + ']')) { if ((currentChar += 3) < endChar) { while (*currentChar != '>') ++currentChar; } else currentChar = endChar; } } else { while (*currentChar != '>') ++currentChar; } if (currentChar != endChar) ++currentChar; } htmlValue = html.Substring((int)(startChar - htmlFixed), (int)(currentChar - startChar) + (*(currentChar - 1) == '>' ? 0 : 1)); children.Add(new htmlNode { TagName = "!", nodeText = new htmlText { FormatHtml = htmlValue, FormatText = htmlValue } }); startChar = currentChar; #endregion } } } else ++currentChar; } } if (startChar != endChar) { *endChar = '>'; while ((*startChar & 0xffc0) == 0 && spaceFixedMap.Get(*startChar)) ++startChar; if (startChar != endChar) { for (scriptChar = endChar - 1; (*scriptChar & 0xffc0) == 0 && spaceFixedMap.Get(*scriptChar); --scriptChar) ; children.Add(new htmlNode { nodeText = new htmlText { FormatHtml = html.Substring((int)(startChar - htmlFixed), (int)(scriptChar - startChar) + 1) } }); } } } for (nextIndex = children.Count - 1; nextIndex != -1; nextIndex--) { nextNode = children[nextIndex]; if (nextNode.nodeText.FormatHtml == null) { if (web.html.MustRoundTagNames.Contains(nextNode.TagName) && (nodeCount = (children.Count - nextIndex - 1)) != 0) { nextNode.children = new list<htmlNode>(children.GetSub(nextIndex + 1, nodeCount), true); children.RemoveRange(nextIndex + 1, nodeCount); foreach (htmlNode value in children) value.Parent = nextNode; } } else if (nextNode.nodeText.FormatHtml.Length == 0) nextNode.nodeText.FormatHtml = null; } foreach (htmlNode value in children) value.Parent = this; } }
/// <summary> /// 删除子节点 /// </summary> /// <param name="node">待删除的子节点</param> /// <returns>是否存在子节点</returns> public bool RemoveChild(htmlNode node) { int index = this[node]; if (index != -1) children.RemoveAt(index); return index != -1; }
/// <summary> /// 解析HTML节点并插入 /// </summary> /// <param name="index">插入位置</param> /// <param name="html"></param> /// <returns>是否插入成功</returns> public bool InsertChild(int index, string html) { bool isInsert = false; if (TagName != null && !web.html.NonanalyticTagNames.Contains(TagName)) { htmlNode value = new htmlNode(html); if (value.children != null) { foreach (htmlNode child in value.children) child.Parent = this; if (children == null) children = value.children; else if (index >= children.Count) children.Add(value.children); else children.Insert(index < 0 ? 0 : index, value.children); } isInsert = true; } return isInsert; }
/// <summary> /// 判断是否存在匹配的子孙节点 /// </summary> /// <param name="node">匹配节点</param> /// <returns>是否存在匹配的子孙节点</returns> public bool IsNode(htmlNode node) { while (node != null && node != this) node = node.Parent; return node != null; }
/// <summary> /// 子节点索引位置 /// </summary> /// <param name="value">子节点</param> /// <returns>索引位置</returns> public int this[htmlNode value] { get { int index = -1; if (value != null && value.Parent == this && children != null) { index = children.Count; while (--index >= 0 && children[index] != value) ; } return index; } }
/// <summary> /// 子节点筛选 /// </summary> /// <param name="path">筛选器</param> /// <param name="value">筛选节点集合</param> /// <returns>匹配的HTML节点集合</returns> private static keyValue<list<htmlNode>, bool> filterChild(filter path, keyValue<list<htmlNode>, bool> value) { if (path.index < 0) { if (path.indexs == null) { if (path.values == null) { if (path.value != null) { string tagName = path.value; list<htmlNode>.unsafer newValues = new list<htmlNode>(value.Key.Count).Unsafer; foreach (htmlNode nodes in value.Key) { if (nodes.children.count() > 0) { foreach (htmlNode node in nodes.children) { if (node.TagName == tagName) newValues.Add(node); } } } return new keyValue<list<htmlNode>, bool>(newValues.List.Count != 0 ? newValues.List : null, value.Value && newValues.List.Count > 1); } else { int index = 0; foreach (htmlNode nodes in value.Key) if (nodes.children != null) index += nodes.children.Count; if (index != 0) { htmlNode[] newValues = new htmlNode[index]; index = 0; foreach (htmlNode nodes in value.Key) { if (nodes.children != null) { nodes.children.CopyTo(newValues, index); index += nodes.children.Count; } } return new keyValue<list<htmlNode>, bool>(new list<htmlNode>(newValues, true), value.Value && newValues.Length != 1); } return new keyValue<list<htmlNode>, bool>(null, false); } } else { staticHashSet<string> tagNames = path.values; list<htmlNode>.unsafer newValues = new list<htmlNode>(value.Key.Count).Unsafer; foreach (htmlNode nodes in value.Key) { if (nodes.children.count() != 0) { foreach (htmlNode node in nodes.children) { if (tagNames.Contains(node.TagName)) newValues.Add(node); } } } return new keyValue<list<htmlNode>, bool>(newValues.List.Count != 0 ? newValues.List : null, value.Value && newValues.List.Count > 1); } } else { list<htmlNode>.unsafer newValues = new list<htmlNode>(value.Key.Count).Unsafer; if (path.value != null) { string tagName = path.value; staticHashSet<int> indexs = path.indexs; foreach (htmlNode nodes in value.Key) { if (nodes.children.count() != 0) { int index = 0; foreach (htmlNode node in nodes.children) { if (node.TagName == tagName) { if (indexs.Contains(index)) newValues.Add(node); ++index; } } } } } else { int[] indexs = path.indexs.GetList().ToArray(); foreach (htmlNode nodes in value.Key) { int count = nodes.children.count(); if (count > 0) { list<htmlNode> children = nodes.children; for (int index = indexs.Length; --index >= 0; ) { if (index < count) newValues.Add(children[index]); } } } } return new keyValue<list<htmlNode>, bool>(newValues.List.Count != 0 ? newValues.List : null, value.Value && newValues.List.Count > 1); } } else { list<htmlNode>.unsafer newValues = new list<htmlNode>(value.Key.Count).Unsafer; if (path.value != null) { string tagName = path.value; int index = path.index; foreach (htmlNode nodes in value.Key) { if (nodes.children.count() != 0) { int count = 0; foreach (htmlNode node in nodes.children) { if (node.TagName == tagName) { if (count == index) { newValues.Add(node); break; } ++count; } } } } } else { int index = path.index; foreach (htmlNode nodes in value.Key) { if (index < nodes.children.count()) newValues.List.Add(nodes.children[index]); } } return new keyValue<list<htmlNode>, bool>(newValues.List.Count != 0 ? newValues.List : null, value.Value && newValues.List.Count > 1); } }