从字符串值中解析产品类别

时间:2015-03-24 14:40:16

标签: c# collections tree string-parsing

更新原始问题,因为我无法清楚地解释自己,人们专注于XML解析而不是我想要的 - 抱歉

我有一个字符串数组,其中包含如下格式的字符串:

A > A1 > A1-1
A > A1 > A1-2
A > A1 > A1-3
A > A2 > A2-1
A > A2 > A2-2
B > B1 > B1-1
C > C1 > C1-1

字符串实际上代表了这样的类别树:

A
|-- A1
|   |-- A1-1
|   |-- A1-2
|   |-- A1-3
|
|-- A2
|   |-- A2-1
|   |-- A2-2
B
|-- B1
|   |-- B1-1
C
|-- C1
|   |-- C1-1

如何将该字符串数组转换为实际包含类别和子类别的集合?我想将该字符串数组转换为 MyCategory对象并将它们放在一个列表中,以便我可以拥有一个产品类别树。

//single category class
public class MyCategory
{
    public string Title {get; set;}
    public IEnumerable<MyCategory> Children {get; set;}
}

3 个答案:

答案 0 :(得分:0)

这里的解析是Example

对于foreach,您可以像XDocument那样使用:

var xml = "<root><product><title>Product Title</product><category>A > A1 > A1-1</category></product><product><title>Product Title</product><category>A > A1 > A1-2</category></product><product><title>Product Title</product><category>A > A2 > A2-1</category></product><product><title>Product Title</product><category>B > B1 > B1-1</category></product></root>";
var doc = XDocument.Parse(xml);

var products = doc.Root.Elements("product");

foreach (var product in products)
{
    var title = product.Element("title").Value;
    var category = product.Element("category").Value;
    var categories = category.Replace(" ",string.Empty).Split('>');
    Console.WriteLine (categories);
}

输出继电器:

enter image description here

答案 1 :(得分:0)

这是一种做法。

   // Single category class
   public class MyCategory
   {
      public string Title { get; set; }
      public Dictionary<string, MyCategory> Children { get; set; }

      // Constructor
      public MyCategory(string title)
      {
         Title = title;
         Children = new Dictionary<string, MyCategory>();
      }
   }


   internal class SO29235482
   {
      // Dictionary for the root nodes
      private readonly Dictionary<string, MyCategory> _categoryTree = 
                                                            new Dictionary<string, MyCategory>();


      public void JustTesting()
      {
         AddCategoryToTree("A > A1 > A1-1");
         AddCategoryToTree("A > A1 > A1-2");
         AddCategoryToTree("A > A1 > A1-3");
         AddCategoryToTree("A > A2 > A2-1");
         AddCategoryToTree("A > A2 > A2-2");
         AddCategoryToTree("B > B1 > B1-1");
         AddCategoryToTree("C > C1 > C1-1");

         if (AddCategoryToTree("C > C1 > C1-1"))
            throw new Exception("Incorrect return value for existing entry.");
      }


      /// <summary>
      /// Method to add (if necessary) a category to the category tree. (No input error checking is 
      /// done - this is simple "proof of concept" code.
      /// </summary>
      /// <param name="textInput">titles separated by '>', for example "A > A1 > A1-1"</param>
      /// <returns>true = category added, false = already in tree</returns>
      public bool AddCategoryToTree(string textInput)
      {
         // Parse the input - no error checking done
         string[] titleArray = textInput.Split('>');

         // Use recursive method to add the nodes to the tree, if not already there
         return AddNodesToTree(titleArray, 0, _categoryTree);
      }


      /// <summary>
      /// Recursive method to process each level in the input string, creating a node if necessary 
      /// and then calling itself to process the next level.
      /// </summary>
      private static bool AddNodesToTree(string[] titleArray, int thisIndex, 
                                         Dictionary<string, MyCategory> priorDictionary)
      {
         if (thisIndex >= titleArray.Length)
            return false;

         bool treeUpdated = false;

         // Create node entry in prior Dictionary if not already there
         string thisTitle = titleArray[thisIndex].Trim();
         MyCategory thisNode;
         if (!priorDictionary.TryGetValue(thisTitle, out thisNode))
         {
            thisNode = new MyCategory(thisTitle);
            priorDictionary.Add(thisTitle, thisNode);
            treeUpdated = true;
         }

         // Process the lower-level nodes using this recursive method
         return AddNodesToTree(titleArray, ++thisIndex, thisNode.Children) | treeUpdated;
      }
   }

我用字典&lt;&gt;替换了你的IEnumerable因为那似乎更自然。但它可以重新编码以使用IEnumerable然后执行Find()而不是通过键直接字典查找。

答案 2 :(得分:0)

我用下面的解决方案解决了我的问题。我是如此专注于服务代码的xml部分我自己也看不到实际的问题。 Rennie的回答让我走上了正确的道路。

这是我从“A&gt; A1&gt; A1-1”格式化字符串数组中获取IEnumerable的方法:

private static void RecurseProductCategories(string[] categoryNames, List<Category> parentList, Category parent = null)
        {
            if (categoryNames.Length > 0)
            {
                var catName = categoryNames[0].Trim();
                var catObject = parentList.SingleOrDefault(f => f.Title == catName);
                if (catObject == null)
                {
                    catObject = new Category { Title = catName, Slug = catName.GenerateSlug(), Parent = parent };
                    parentList.Add(catObject);
                }

                RecurseProductCategories(categoryNames.Skip(1).ToArray(), catObject.Children, catObject);
            }
        }

这个递归函数在我这样调用时给了我想要的东西:

string[] demoArray = new string[]
{
    "A > A1 > A1-1",
    "A > A1 > A1-2",
    "A > A2 > A2-1",
    "B > B1"
}

var categoryList = new List<Category>();

for(int i=0; i < demoArray.Length; i++)
{
    string[] categoryStringSplit = demoArray[i].Split('>');
    RecurseProductCategories(categoryStringSplit, categoryList);
}