最后LINQ to XML递归查看元素

时间:2013-01-20 11:25:25

标签: c# .net linq-to-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();
    }

在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

如何编辑代码?从昨天开始真的挣扎......

3 个答案:

答案 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
}