从字符串值解析产品类别

Parsing product categories from string value

更新原始问题,因为我无法清楚地解释自己,人们专注于 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;}
}

这里的解析是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);
}

输出:

这是一种方法。

   // 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;
      }
   }

我已将您的 IEnumerable 替换为 Dictionary<>,因为这看起来更自然。但它可以重新编码为使用 IEnumerable,然后执行 Find() 而不是通过键直接查找字典。

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

这就是我从 "A > A1 > 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);
}