我写道:
public string GetOutline(int indentLevel, XElement element)
{
StringBuilder result = new StringBuilder();
result = result.AppendLine(new string('-', indentLevel * 2) + element.Name);
foreach (var childElement in element.Elements())
{
result.Append(GetOutline(indentLevel + 3, childElement));
}
return result.ToString();
}
在xml文件上运行此递归方法的结果显示:
Videos
------Video
------------Title
------------Director
------------Actors
------------------Actor
------------------Actor
------------------Actor
------------------Actor
------------Length
------------Format
------------Rating
------Video
------------Title
------------Director
------------Length
------------Format
------------Rating
enter code here
但我希望输出如下:
Videos
------Video
------------Title
------------Director
------------Actors
------------------Actor
------------Length
------------Format
------------Rating
如何编辑代码?从昨天开始真的挣扎......
答案 0 :(得分:1)
按名称使用linq分组:
foreach (var childElement in element.Elements().GroupBy(childElement => childElement.Name))
{
result.Append(GetOutline(indentLevel + 3, childElement.First()));
}
而不是:
foreach (var childElement in element.Elements())
{
result.Append(GetOutline(indentLevel + 3, childElement.First()));
}
此方法的唯一问题是使用First
。
例如,如果您有XML文件:
<actors>
<actor>
<property/>
</actor>
<actor>
<differentProperty/>
<differentProperty2/>
</actor>
</actors>
使用分组和First
结果将是:
actors
----actor
--------property
在这种情况下,您希望结果如何显示?
actors
----actor
--------property
--------differentProperty
--------differentProperty2
或
actors
----actor
--------property
----actor
--------differentProperty
--------differentProperty2
或者这种情况不会出现?
鉴于您的评论,解决方案将是:
public static string GetOutline(int indentLevel, XElement element)
{
return GetGroupOutline(indentLevel, new[] {element});
}
/// <summary>
/// Returns the outline of the elements that constitute a group.
/// </summary>
/// <param name="indentLevel">Indent level.</param>
/// <param name="elements">Elements of a group (all the element of the collection must have the same <c>Name</c>)</param>
/// <returns>Outline of the group.</returns>
private static string GetGroupOutline(int indentLevel, IEnumerable<XElement> elements)
{
StringBuilder result = new StringBuilder();
// Adds the group name in the outline
result = result.AppendLine(new string('-', indentLevel * 6) + elements.First().Name);
foreach (var childGroup in from element in elements // Gets each element in the group "elements"
from childElement in element.Elements() // Gets their children
group childElement by childElement.Name into childGroup // Groups the children of all elements by their name to a new group called "childGroup"
select childGroup)
result.Append(GetGroupOutline(indentLevel + 1, childGroup)); // Shows the outline of the group called "groupChild"
return result.ToString();
}
答案 1 :(得分:0)
您需要首先使用所有唯一元素构建xml树:
private XElement GetUniqueElementsOf(XDocument xdoc)
{
XElement result = new XElement(xdoc.Root.Name);
AddUniqueChildren(result, xdoc.Root);
return result;
}
public void AddUniqueChildren(XElement dest, XElement source)
{
foreach (XElement sourceChild in source.Elements())
{
var destChild = dest.Elements()
.SingleOrDefault(x => x.Name == sourceChild.Name);
if (destChild == null)
{
destChild = new XElement(sourceChild.Name);
dest.Add(destChild);
}
AddUniqueChilds(destChild, sourceChild);
}
}
第二种方法将通过递归遍历xml将所有唯一子元素添加到每个节点。此时您需要做的就是输出结果:
var result = GetOutline(0, GetUniqueElementsOf(XDocument.Load(path_to_xml)));
大纲方法应该简单,没有分组(因为我们已经只有xml的唯一元素):
public string GetOutline(int indentLevel, XElement element)
{
StringBuilder result = new StringBuilder();
result = result.AppendLine(new string('-', indentLevel * 2) + element.Name);
foreach (var childElement in element.Elements())
result.Append(GetOutline(indentLevel + 3, childElement));
return result.ToString();
}
答案 2 :(得分:0)
internal static class ExtensionMethods
{
public static List<XElement> Find(this XElement _objXElement, string _strFindXName)
{
List<XElement> _lsXElementsFound = new List<XElement>();
try
{
List<XElement> _lsXElementsBundle = new List<XElement>();
RecursiveSearch(_objXElement, _strFindXName, ref _lsXElementsBundle);
if (_lsXElementsBundle != null && _lsXElementsBundle.Count > 0)
{
foreach (XElement _objCurrentXElement in _lsXElementsBundle)
{
if (_objCurrentXElement != null)
{
if (!string.IsNullOrEmpty(_objCurrentXElement.Value))
{
_lsXElementsFound.Add(_objCurrentXElement);
}
else
{
_objCurrentXElement.Value = string.Empty;
_lsXElementsFound.Add(_objCurrentXElement);
}
}
}
}
}
catch (Exception _objException)
{
_lsXElementsFound = new List<XElement>();
string _strDescription = NLOG.Utility.FormatEvent(MethodBase.GetCurrentMethod()
, _objException.Message);
NLOG.Log.Error(_strDescription);
}
return _lsXElementsFound;
}
#region "SUPPORT"
private static void RecursiveSearch(XElement _objXElement, string _strFindXName
, ref List<XElement> _lsOfXElementsFound)
{
try
{
if (_objXElement != null && !string.IsNullOrEmpty(_strFindXName)
&& _lsOfXElementsFound != null)
{
if (_objXElement.Name == _strFindXName)
{
_lsOfXElementsFound.Add(_objXElement);
}
else
{
foreach (XElement _objCurrentXElement in _objXElement.Elements())
{
RecursiveSearch(_objCurrentXElement, _strFindXName, ref _lsOfXElementsFound);
}
}
}
}
catch (Exception _objException)
{
string _strDescription = NLOG.Utility.FormatEvent(MethodBase.GetCurrentMethod()
, _objException.Message);
NLOG.Log.Error(_strDescription);
}
}
#endregion
}