找到顶级分类父级,在示例JSON中使用Java添加相应父级下方的子级。

huangapple go评论117阅读模式
英文:

Find top category parent and add child below respective parent in sample JSON using java

问题

我在下面的URL上找到了这个样本电子商务JSON。我想按层次对这个JSON进行整理。

你可以在以下URL上找到这个JSON文件。

https://stark-spire-93433.herokuapp.com/json

我想按以下方式对这个JSON进行排列。

  1. 男装
  2. |下装
  3. |牛仔裤
  4. |运动裤和长裤
  5. |鞋类
  6. |休闲鞋
  7. |正装鞋
  8. |上装
  9. |衬衫
  10. |T
  11. 电子产品
  12. |手机
  13. |苹果
  14. |三星
  15. |笔记本电脑
  16. |戴尔
  17. |东芝

所有变体都将位于产品的最后层次下。例如Dell、Apple、衬衫等。

我已经为这个JSON创建了模型类。

  1. public class Data {
  2. public ArrayList<Category> categories;
  3. public ArrayList<Rank> rankings;
  4. }
  5. public class Category {
  6. public int id;
  7. public String name;
  8. public ArrayList<Product> products;
  9. public ArrayList<Integer> child_categories;
  10. }
  11. public class Rank {
  12. public String ranking;
  13. public ArrayList<Product> products;
  14. }
  15. public class Product {
  16. public int id;
  17. public String name;
  18. public String date_added;
  19. public ArrayList<Variant> variants;
  20. public Tax tax;
  21. public int view_count;
  22. public int order_count;
  23. public int shares;
  24. }
  25. public class Tax {
  26. public String name;
  27. public double value;
  28. }
  29. public class Variant {
  30. public int id;
  31. public String color;
  32. //对于某些变体,大小为null,例如手机,如果为null,则传递0。
  33. public int size;
  34. public double price;
  35. }

现在我不知道该如何开始。

英文:

I found this sample eCommerce JSON. I wanted to arrange this JSON in hierarchically.

You can find this JSON file on below URL.

https://stark-spire-93433.herokuapp.com/json

I wanted to arrange this JSON in the following manner.

  1. Mens Wear
  2. |Bottom Wear
  3. |Jeans
  4. |Tracks & Trousers
  5. |Foot Wear
  6. |Casuals
  7. |Formals
  8. |Upper Wear
  9. |Shirts
  10. |T-Shirts
  11. Electronics
  12. |Mobiles
  13. |Apple
  14. |Samsung
  15. |Laptops
  16. |Dell
  17. |Toshiba

All variants will go under the last hierarchy of products. For example Dell, Apple, Shirts and so on.

I have created model classes for this JSON.

  1. public class Data {
  2. public ArrayList<Category> categories;
  3. public ArrayList<Rank> rankings;
  4. }
  5. public class Category {
  6. public int id;
  7. public String name;
  8. public ArrayList<Product> products;
  9. public ArrayList<Integer> child_categories;
  10. }
  11. public class Rank {
  12. public String ranking;
  13. public ArrayList<Product> products;
  14. }
  15. public class Product {
  16. public int id;
  17. public String name;
  18. public String date_added;
  19. public ArrayList<Variant> variants;
  20. public Tax tax;
  21. public int view_count;
  22. public int order_count;
  23. public int shares;
  24. }
  25. public class Tax {
  26. public String name;
  27. public double value;
  28. }
  29. public class Variant {
  30. public int id;
  31. public String color;
  32. //in some variants size is null eg. mobiles, if null pass 0.
  33. public int size;
  34. public double price;
  35. }

Now I don't understand how should I start.

答案1

得分: 0

问题在于使用间接引用通过ID引用子类别。目标是将这些间接引用转换为直接引用,类似于 data.getCategory().getChildCategory().getName() 这样的形式。

我会通过引入两个抽象层来解决这个问题:

第一个层仅用于反序列化。我们称这些类为 JsonBean,它们的结构与JSON的结构非常相似,所以子类别只是数字。这还有一个优点,就是 JsonBean 可以包含用于反序列化的特殊注解,就像 Jackson 所使用的那样。

第二个层将是应用程序中使用的对象图,它会用具体的对象替换子类别。我们简单地将这种类型的类称为 Bean。这些 Bean 与JSON的设计无关,这样即使从数据库加载数据而不是JSON,它们也可以被重用。

反序列化过程将分为两个步骤:首先是原始的反序列化为 JsonBean。然后是一个转换服务,将 JsonBean 复制到应用程序的 Bean 中。这个转换将会将子类别的ID解析为具体的 Category 对象。

纯值模型和持久化模型之间的分离也可以在JSON的结构将来发生变化时提供一些安全性。只要变化不是太大,这对于你的应用程序影响较小,因为你只需要更改 JsonBean 和转换逻辑,而不必更改反序列化后使用数据的所有其他内容。

英文:

Well, the problem is the usage of indirect references to child-categories using ids. The goal would be to transform the indirect references to direct references such as something like data.getCategory().getChildCategory().getName() is possible.

I would solve this by introducing two abstraction layers:

The first one exists only for deserialization. The classes - let's call them JsonBeans - of this layer would closely resemble the structure of the json, so the child-categories are only numbers. This also has the advantage that the JsonBeans could contain special annotations for deserialization like they are used by Jackson.

The second layer will be the object graph that is used in the application and it replaces the child-categories with concrete objects. Let's simply call this type of classes Bean. The Beans would be independent from the design of the JSON, in such a way, that they could be reused even if the data is loaded from a database instead of a JSON.

The deserialization process would then have two steps: First the raw deserialization into JsonBeans. Then followed by a transformation service that would copy the JsonBeans to the application Beans. This transformation would then resolve the ids of the child-categories to concrete Category-objects.

The separation between the pure value model and the persistence model also gives some safety in case the JSON's structure is changed in the future. As long as the change is not too severe, this would have little effect on your application, since you would only need to change the JsonBeans and the transformation - not everything else that uses the data after the deserialization.

答案2

得分: 0

这是我的解决方案

概要

  1. 修改了文章中的类模型 - 使用[组合设计模式][1]添加了树结构
  2. 使用Jackson库将JSON反序列化为文章中的类模型。
  3. 构建一个Map<Integer, Category>,允许通过其ID直接访问类别
  4. 遍历类别,对于每个类别,遍历其子类别,对于每个子类别ID,从映射中获取子类别并分配为子实例
  5. 最后,使用[深度优先搜索][2]遍历树并使用[访问者模式][3]打印类别

数据结构

我拿了你的模型并做了一些修改:

  1. 将列表更改为接口定义。这是因为变量构建是由JSON反序列化器执行的,可能决定使用List的不同实现。
  2. 添加了用于实现组合模式的集合:每个Category都有子类别的列表作为Category实例,Data添加了树根的列表。
  3. 更改了变量名称以更好地反映用途和使用。

以下是修改后的DataCategory类的外观:

  1. public class Category
  2. {
  3. public int id;
  4. public String name;
  5. public List<Product> products;
  6. @JsonProperty("child_categories")
  7. public List<Integer> childCategoryIds;
  8. // 树结构属性
  9. public boolean isRoot = true;
  10. public List<Category> childCategories = new ArrayList<>();
  11. public void visit(Visitor<Category> visitor, int level) {
  12. visitor.accpet(this, level);
  13. childCategories.forEach(cat -> cat.visit(visitor, level + 1));
  14. }
  15. }
  16. public class Data
  17. {
  18. public List<Category> categories;
  19. public List<Rank> rankings;
  20. // 树结构属性
  21. public List<Category> tree;
  22. // 使用打印机访问者启动每个根的遍历
  23. public void printTree() {
  24. Visitor<Category> printer = new Printer();
  25. tree.forEach(root -> root.visit(printer, 0));
  26. }
  27. }

解决方案实施

访问者模式

  1. // 访问者接口
  2. public interface Visitor<T>
  3. {
  4. /**
  5. * @param level 0表示根,1表示根的子类别,依此类推
  6. */
  7. public void accpet(T node, int level);
  8. }
  9. // 打印机访问者:适当缩进地将每个访问的类别打印到控制台
  10. public class Printer implements Visitor<Category>
  11. {
  12. @Override
  13. public void accpet(Category node, int level) {
  14. System.out.println(indentByLevel(level) + node.id + " " + node.name);
  15. // 如果有产品的类别 - 打印它们和变体
  16. if (node.products != null && !node.products.isEmpty()) {
  17. printProducts(node, level);
  18. }
  19. }
  20. private void printProducts(Category node, int level) {
  21. node.products.forEach(product -> {
  22. System.out.println(indentByLevel(level+1) + product.id + " " + product.name);
  23. if (product.variants != null && !product.variants.isEmpty()) {
  24. product.variants.forEach(variant -> {
  25. System.out.println(indentByLevel(level+2) + variant.id + " " + variant.color);
  26. });
  27. }
  28. });
  29. }
  30. private static final String levelIndent = " ";
  31. private String indentByLevel(int level) {
  32. if (level > 0) {
  33. return String.join("", Collections.nCopies(level, levelIndent));
  34. }
  35. return "";
  36. }
  37. }

主类

  1. public class JsonToTree
  2. {
  3. public static void main(String[] args) {
  4. try {
  5. Data data = readJson("https://stark-spire-93433.herokuapp.com/json");
  6. jsonToTree(data);
  7. data.printTree();
  8. } catch (Exception e) {
  9. e.printStackTrace();
  10. }
  11. }
  12. // 读取和解析源到Data对象
  13. // 使用Java 11的HttpURLConnection和Jackson ObjectMapper
  14. public static Data readJson(String url) throws IOException {
  15. HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
  16. connection.setRequestMethod("GET");
  17. try (InputStream responseStream = connection.getInputStream()) {
  18. ObjectMapper mapper = new ObjectMapper();
  19. return mapper.readValue(responseStream, Data.class);
  20. }
  21. }
  22. public static void jsonToTree(Data data) {
  23. // 填充类别数组。数组索引是类别ID
  24. // 这将允许通过其ID随机访问类别
  25. Map<Integer, Category> categoryById = data.categories.stream()
  26. .collect(Collectors.toMap(cat -> cat.id, Function.identity(), (cat1, cat2) -> cat1));
  27. // 根据子ID列表为每个类别对象填充类别对象的列表
  28. // 在此过程中,将每个子类别标记为非根
  29. data.categories.stream()
  30. .filter(cat -> cat.childCategoryIds != null && !cat.childCategoryIds.isEmpty())
  31. .forEach(catWithChildren ->
  32. catWithChildren.childCategoryIds.forEach(id -> {
  33. Category child = categoryById.get(id);
  34. if (child != null) {
  35. catWithChildren.childCategories.add(child);
  36. child.isRoot = false;
  37. }
  38. })
  39. );
  40. // 从根类别构建树
  41. data.tree = new ArrayList<>();
  42. data.categories.stream()
  43. .filter(cat -> cat.isRoot)
  44. .forEach(root -> data.tree.add(root));
  45. }
  46. }

输出

  1. 3 Mens Wear
  2. 4 Bottom Wear
  3. 2 Jeans
  4. 3 Spykar Denim
  5. 9 Blue
  6. 10 Black
  7. 11 Blue
  8. 12 Blue
  9. 4 Lee Cotton Jeans
  10. 13 Blue
  11. 14 Black
  12. 15 White
  13. 16 Black
  14. 24 Denim Wash
  15. 71 Blue
  16. <details>
  17. <summary>英文:</summary>
  18. Here is my solution
  19. Outline
  20. ----
  21. 1. modify the class model from the post - add tree structure using [Composite design pattern][1]
  22. 1. deserialize the json into the class model from the post using Jackson library.
  23. 1. build a `Map&lt;Integer, Category&gt;` that allows direct access to category by its id
  24. 1. iterate over the categories, for each one, iterate over its children, for each child id, get the child category from the map and assign as child instance
  25. 1. finally, iterate over the tree using [depth first search][2] and print the categories using [visitor pattern][3]
  26. Data Structure
  27. ----
  28. I took your model and modified a little bit:
  29. 1. Changed lists to be defined as the interface. this is since the variable construction is performed by the json deserializer that may decide to use a different implementation of `List`
  30. 1. Added collections for the implementation of Composite pattern: each `Category` has list of child categories as `Category` instances, `Data` was added list of tree roots.
  31. 1. Changed variable names to better reflect purpose and usage.
  32. Here is how the modified `Data` and `Category` classes look like:
  33. public class Category
  34. {
  35. public int id;
  36. public String name;
  37. public List&lt;Product&gt; products;
  38. @JsonProperty(&quot;child_categories&quot;)
  39. public List&lt;Integer&gt; childCategoryIds;
  40. // tree-structure properties
  41. public boolean isRoot = true;
  42. public List&lt;Category&gt; childCategories = new ArrayList&lt;&gt;();
  43. public void visit(Visitor&lt;Category&gt; visitor, int level) {
  44. visitor.accpet(this, level);
  45. childCategories.forEach(cat -&gt; cat.visit(visitor, level + 1));
  46. }
  47. }
  48. public class Data
  49. {
  50. public List&lt;Category&gt; categories;
  51. public List&lt;Rank&gt; rankings;
  52. // tree-structure properties
  53. public List&lt;Category&gt; tree;
  54. // initiate traversal of each root withj printer visitor
  55. public void printTree() {
  56. Visitor&lt;Category&gt; printer = new Printer();
  57. tree.forEach(root -&gt; root.visit(printer, 0));
  58. }
  59. }
  60. Solution Implementation
  61. ----
  62. **Visitor Pattern**
  63. // visitor interface
  64. public interface Visitor&lt;T&gt;
  65. {
  66. /**
  67. * @param level 0 is root, 1 root&#39;s child and so on
  68. */
  69. public void accpet(T node, int level);
  70. }
  71. // printer visitor: prints to console each visited category, properly indented
  72. public class Printer implements Visitor&lt;Category&gt;
  73. {
  74. @Override
  75. public void accpet(Category node, int level) {
  76. System.out.println(indentByLevel(level) + node.id + &quot; &quot; + node.name);
  77. // in case of category with products - print them and variants
  78. if (node.products != null &amp;&amp; !node.products.isEmpty()) {
  79. printProducts(node, level);
  80. }
  81. }
  82. private void printProducts(Category node, int level) {
  83. node.products.forEach(product -&gt; {
  84. System.out.println(indentByLevel(level+1) + product.id + &quot; &quot; + product.name);
  85. if (product.variants != null &amp;&amp; !product.variants.isEmpty()) {
  86. product.variants.forEach(variant -&gt; {
  87. System.out.println(indentByLevel(level+2) + variant.id + &quot; &quot; + variant.color);
  88. });
  89. }
  90. });
  91. }
  92. private static final String levelIndent = &quot; &quot;;
  93. private String indentByLevel(int level) {
  94. if (level &gt; 0) {
  95. return String.join(&quot;&quot;, Collections.nCopies(level, levelIndent));
  96. }
  97. return &quot;&quot;;
  98. }
  99. }
  100. **Main class**
  101. public class JsonToTree
  102. {
  103. public static void main(String[] args) {
  104. try {
  105. Data data = readJson(&quot;https://stark-spire-93433.herokuapp.com/json&quot;);
  106. jsonToTree(data);
  107. data.printTree();
  108. } catch (Exception e) {
  109. e.printStackTrace();
  110. }
  111. }
  112. // read and parse source to Data object
  113. // using java 11 HttpURLConnection and Jackson ObjectMapper
  114. public static Data readJson(String url) throws IOException {
  115. HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
  116. connection.setRequestMethod(&quot;GET&quot;);
  117. try (InputStream responseStream = connection.getInputStream()) {
  118. ObjectMapper mapper = new ObjectMapper();
  119. return mapper.readValue(responseStream, Data.class);
  120. }
  121. }
  122. public static void jsonToTree(Data data) {
  123. // populate array of categories. array index is category id
  124. // this will allow random access to category by its id
  125. Map&lt;Integer, Category&gt; categoryById = data.categories.stream()
  126. .collect(Collectors.toMap(cat -&gt; cat.id, Function.identity(), (cat1, cat2) -&gt; cat1));
  127. // populate list of category objects for each category according to list of child ids
  128. // along the way, mark each child category as not root
  129. data.categories.stream()
  130. .filter(cat -&gt; cat.childCategoryIds != null &amp;&amp; !cat.childCategoryIds.isEmpty())
  131. .forEach(catWithChildren -&gt;
  132. catWithChildren.childCategoryIds.forEach(id -&gt; {
  133. Category child = categoryById.get(id);
  134. if (child != null) {
  135. catWithChildren.childCategories.add(child);
  136. child.isRoot = false;
  137. }
  138. })
  139. );
  140. // build tree in data from root categories
  141. data.tree = new ArrayList&lt;&gt;();
  142. data.categories.stream()
  143. .filter(cat -&gt; cat.isRoot)
  144. .forEach(root -&gt; data.tree.add(root));
  145. }
  146. }
  147. Printout
  148. ----
  149. 3 Mens Wear
  150. 4 Bottom Wear
  151. 2 Jeans
  152. 3 Spykar Denim
  153. 9 Blue
  154. 10 Black
  155. 11 Blue
  156. 12 Blue
  157. 4 Lee Cotton Jeans
  158. 13 Blue
  159. 14 Black
  160. 15 White
  161. 16 Black
  162. 24 Denim Wash
  163. 71 Blue
  164. 72 Grey
  165. 25 Pepe Jeans Slim Fit
  166. 73 Blue
  167. 74 Light Blue
  168. 26 Spykar Funky Regular
  169. 75 Blue
  170. 76 Black
  171. 8 Tracks &amp; Trousers
  172. 7 Comfort Tracks
  173. 25 Blue
  174. 26 Red
  175. 27 White
  176. 28 Red
  177. 8 Adidas Trousers
  178. 29 White
  179. 30 Yellow
  180. 31 Green
  181. 32 Red
  182. 30 Superdry track
  183. 83 Red
  184. 84 Blue
  185. 31 Night Comfy Track
  186. 85 Red
  187. 86 Black
  188. 32 Superdry Joggers
  189. 87 Red
  190. 88 Blue
  191. 5 Foot Wear
  192. 1 Casuals
  193. 1 Nike Sneakers
  194. 1 Blue
  195. 2 Red
  196. 3 Blue
  197. 4 Red
  198. 2 Adidas Running Shoes
  199. 5 White
  200. 6 Black
  201. 7 White
  202. 8 Red
  203. 21 Roadster Loafers
  204. 65 Black
  205. 66 Blue
  206. 22 Light Loafers
  207. 67 Blue
  208. 68 Yellow
  209. 23 Floaters
  210. 69 Black
  211. 70 Red
  212. 9 Formals
  213. 9 Bata Lace up Shoes
  214. 33 Black
  215. 34 Brown
  216. 35 Black
  217. 36 Brown
  218. 10 Franco Leather
  219. 37 Black
  220. 38 Brown
  221. 39 Black
  222. 40 Brown
  223. 6 Upper Wear
  224. 7 T-Shirts
  225. 5 Polo Collar T-Shirt
  226. 17 Blue
  227. 18 Red
  228. 19 White
  229. 20 Red
  230. 6 Adidas Nylon
  231. 21 White
  232. 22 Yellow
  233. 23 Green
  234. 24 Red
  235. 27 Being Human Collar T-shirt
  236. 77 Blue
  237. 78 Black
  238. 28 V - Neck Smart T-Shirt
  239. 79 Blue
  240. 80 Black
  241. 29 Manchester United
  242. 81 Red
  243. 82 Red
  244. 10 Shirts
  245. 11 Wrangler Checked Shirt
  246. 41 Blue
  247. 42 Red
  248. 43 Black
  249. 44 White
  250. 12 Printed Shirt
  251. 45 Blue
  252. 46 Black
  253. 47 Red
  254. 48 Brown
  255. 11 Electronics
  256. 12 Mobiles
  257. 14 Apple
  258. 13 Iphone 6S
  259. 49 Silver
  260. 50 Golden
  261. 14 Iphone 7
  262. 51 Black
  263. 52 Silver
  264. 33 Iphone 6
  265. 89 Silver
  266. 90 Golden
  267. 34 Iphone 6s Plus
  268. 91 Silver
  269. 92 Golden
  270. 35 Iphone 7 Plus
  271. 93 Black
  272. 94 Grey
  273. 15 Samsung
  274. 15 Galaxy S7 Edge
  275. 53 Black
  276. 54 White
  277. 16 Galaxy J5
  278. 55 Black
  279. 56 White
  280. 36 Galaxy J7
  281. 95 Black
  282. 96 White
  283. 37 Galaxy Grand Prime
  284. 97 Black
  285. 98 White
  286. 38 Note 4
  287. 99 Black
  288. 100 White
  289. 13 Laptops
  290. 16 Dell
  291. 17 Dell Inspiron Core
  292. 57 Black
  293. 58 Red
  294. 18 Dell Inspiron 11
  295. 59 Black
  296. 60 Red
  297. 17 Toshiba
  298. 19 Satellite Pro
  299. 61 Black
  300. 62 Red
  301. 20 Satellite P50
  302. 63 Black
  303. 64 Red
  304. [1]: https://en.wikipedia.org/wiki/Composite_pattern
  305. [2]: https://en.wikipedia.org/wiki/Depth-first_search
  306. [3]: https://en.wikipedia.org/wiki/Visitor_pattern
  307. </details>

huangapple
  • 本文由 发表于 2020年9月10日 15:05:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/63824439.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定