DataWeave에서 JSON 객체를 재귀 적으로 트래버스하고 평면화합니다.
제품 계층 구조를 보여주는 다음과 같은 구조를 가진 큰 JSON 파일을 탐색하고 평평하게 만들고 싶습니다 (온라인 상점의 탐색으로 생각하십시오).
productGroups: [
{
"key": "child 1"
...
"childrenProductGroups": [
{
"key": "child 1.1",
...,
"childrenProductGroups": []
},
{
"key": "child 1.2"
...
"childrenProductGroups": [
{
"key": "child 1.2.1",
...,
"childrenProductGroups": [
{
"key": "child 1.2.1.1",
...,
childrenProductGroups": [
...
]
}
]
},
{
"key": "child 1.2.2",
...,
"childrenProductGroups": []
}
]
},
{
"key": "child 1.3",
...,
"childrenProductGroups": [
...
]
}
]
},
{
"key": "child 2",
...,
"childrenProductGroups": [
...
]
},
{
"key": "child 3",
...,
"childrenProductGroups": [
...
]
}
]
다음과 같은 형식으로 평면화하고 싶습니다.
{
"hierarchieSet": [
{
"Nodeid": "00000001", # Number in this json
"Nodename": "child 1",
"Tlevel": "01", # First child of product group
"Parentid": "00000000", # Parent is null
"Childid": "00000002", # Child node number
"Nextid": "00000008" # Node number on the same level (child 2)
},
{
"Nodeid": "00000002",
"Nodename": "child 1.1",
"Tlevel": "02",
"Parentid": "00000001",
"Childid": "00000003",
"Nextid": "00000003"
},
{
"Nodeid": "00000003",
"Nodename": "child 1.2",
"Tlevel": "02",
"Parentid": "00000002",
"Childid": "00000005",
"Nextid": "00000007"
},
{
"Nodeid": "00000004",
"Nodename": "child 1.2.1",
"Tlevel": "03",
"Parentid": "00000003",
"Childid": "0000005",
"Nextid": "00000006"
}
,
{
"Nodeid": "00000005",
"Nodename": "child 1.2.1.1",
"Tlevel": "04",
"Parentid": "00000004",
"Childid": "0000000", #No more children
"Nextid": "00000000"
},
{
"Nodeid": "00000006",
"Nodename": "child 1.2.2",
"Tlevel": "03",
"Parentid": "00000003",
"Childid": "0000000",
"Nextid": "00000000"
},
{
"Nodeid": "00000007",
"Nodename": "child 1.3",
"Tlevel": "02",
"Parentid": "00000001",
"Childid": "0000000",
"Nextid": "00000000"
},
{
"Nodeid": "00000008",
"Nodename": "child 2",
"Tlevel": "01",
"Parentid": "00000000",
"Childid": "0000009", # 00000009 not shown
"Nextid": "00000014" #
},
...
{
"Nodeid": "000000014",
"Nodename": "child 3",
"Tlevel": "01",
"Parentid": "00000000",
"Childid": "00000015",
"Nextid": "00000000" # 00000010 does not exist
}
]
}
따라서 몇 가지 주요 우려 사항을 확인했습니다.
- 트리 구조의 재귀
- 요소 변형
- 구조 평평하게하기
- 부모, 형제 자매 및 자녀 추적
- 재귀 수준 추적
- 숫자 서식
저는이 문제를 두 가지 다른 접근 방식으로 해결하려고했습니다.
- DataWeave를 사용하여 모든 요소 변환
- Java를 사용하여 구조 탐색
함수형 프로그래밍을 처음 접했기 때문에 Java 구현에 더 중점을 두었지만 여러 문제가 발생했습니다.
자바 접근

읽기 JSON> 초기화 나무 VAR 및 최상위 배열 호출의 각 요소에 대해> 자바 인스턴스를 할당
traverse(data, level)
에 Tree.java
. Tree.java :
import org.json.JSONObject;
public class Tree {
private int id = 0;
private List<Node> nodes = new ArrayList<Node>();
public Tree() {
nodes.add(new Node("01", "00000001", "HOME", "01", "00000000", "00000002", "00000000"));
}
public void traverse(String data, int level) {
System.out.println(data);
// TODO parse json
}
private void visit(JSONObject parent, JSONObject node, int level) {
id++;
nodes.add(new Node("01", String.valueOf(id), node.getString("key"), String.valueOf(level), "", "", ""));
}
public List<Node> getNodes() {
return nodes;
}
private static class Node {
private String zshop, nodename, parentid, childid, nextid, nodeid, tlevel;
public Node(String zshop, String nodeid, String nodename, String tlevel, String parentid, String childid, String nextid) {
this.zshop = zshop;
this.nodeid = nodeid;
this.nodename = nodename;
this.tlevel = tlevel;
this.parentid = parentid;
this.childid = childid;
this.nextid = nextid;
}
}
}
invoke 작업을 호출 할 때이 페이로드를 사용합니다.
%dw 2.0
output application/java
---
{
data: vars.rootMessage.payload as String,
level: 1
}
그러나 이로 인해 다음과 같은 오류가 발생합니다.
"Object {encoding : UTF-8, mediaType : text / json; charset = UTF-8, mimeType : text / json, raw : org.mule.weave.v2.el.SeekableCursorStream@50ecee52} (org.mule. weave.v2.el.MuleTypedValue@511ba9cc)를 문자열로
5 | data : vars.rootMessage.payload as String, ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Trace : at main (line : 5, column : 7) "평가 표현식 :"% dw 2.0 output application / java --- {data : vars.rootMessage.payload as String, level : 1} ".
나는 많은 것을 시도했다 :
ProductGroup
Java로 작성한 객체로 캐스트- 검색된 개체를
org.json.JSONObject
- 버퍼링 및 읽기 시도
vars.rootMessage.payload (Binary)
그러나 나는 이러한 문제로 해결할 수 없었습니다.
DataWeave 접근 방식 내 .dw 스크립트
%dw 2.0
fun append
(item: Object, acc: Object = {
}) = acc ++ item
fun mapper(item: Object) =
{
Zshop: "01",
Nodeid: "00000000",
Nodename: item.key as Number as String {format: ""},
Tlevel: "02",
Parentid: "00000000",
Childid: "00000000",
Nextid: "00000000"
}
fun traverse(a: Array, level: Number) =
a map $ flatMap(value, index) -> value
output application/json
---
{
test: payload.productGroups reduce (item, acc) -> append(mapper(item), acc)
}
몇 가지 문제를 해결하려고 노력했습니다. mapper(item)
을 사용하여 최종 출력에 추가 할 수있는 json 객체를 만들어야합니다 appender(item, acc)
. 재귀는 스케치되었지만 아직 내 주요 관심사는 아닙니다.
결과는 다음과 같습니다.
(original payload),
"Zshop": "01",
"Nodeid": "00000000",
"Nodename": "800",
"Tlevel": "02",
"Parentid": "00000000",
"Childid": "00000000",
"Nextid": "00000000",
"Zshop": "01",
"Nodeid": "00000000",
"Nodename": "110",
"Tlevel": "02",
"Parentid": "00000000",
"Childid": "00000000",
"Nextid": "00000000",
"Zshop": "01",
"Nodeid": "00000000",
"Nodename": "720",
"Tlevel": "02",
"Parentid": "00000000",
"Childid": "00000000",
"Nextid": "00000000",
"Zshop": "01",
"Nodeid": "00000000",
"Nodename": "710",
"Tlevel": "02",
"Parentid": "00000000",
"Childid": "00000000",
"Nextid": "00000000",
...
객체 구조없이 평평한 결과를 얻는 이유가 궁금합니다.
내 질문 :
- 자바 : 문자열을 캐스트 할 수없는 이유 또는 제대로 수행되는 방법
- DataWeave : 보이지 않는 쉬운 솔루션이 있습니까?
- 개체가 아닌 평평한 결과 인 이유는 무엇입니까?
reduce
및flatMap
기능 의 사용법 이이 목적에 맞습니까?
모든 도움 및 / 또는 피드백을 환영합니다.
답변
자바 : 문자열을 캐스트 할 수없는 이유 또는 제대로 수행되는 방법
JSON은 문자열이 아닙니다. write (payload, 'application / json')을 사용하여 String.
DataWeave : 보이지 않는 쉬운 솔루션이 있습니까?
객체를 전달하면 Java의 Map입니다. 나무이기 때문에-각 가지는이지도 안에있는 또 다른지도입니다.
개체가 아닌 평평한 결과 인 이유는 무엇입니까?
항상 개체입니다. Java 세계에는 다른 것이 없습니다.
reduce 및 flatMap 함수의 사용법이이 목적에 맞습니까?
아니요. mapObject와 재귀는 좋은 접근 방식이어야합니다.
내가받은 도움을 바탕으로이 솔루션을 만들 수있었습니다.
public class Tree implements Serializable {
private int id = 0;
private List<Node> nodes = new ArrayList<Node>();
public Tree() {
nodes.add(new Node("01", "00000001", "HOME", "0", "00000000", "00000002", "00000000"));
}
public void enter(String jsonString, Integer level) {
JSONObject json = new JSONObject(jsonString);
traverse(json, level);
}
public void traverse(JSONObject json, int level) {
visit(json, level);
JSONArray arr = json.getJSONArray("childProductGroups");
if(arr != null) {
for(int i = 0; i < arr.length(); i++) {
traverse(arr.getJSONObject(i), level + 1);
}
}
}
private void visit(JSONObject object, int level) {
id++;
nodes.add(new Node("01", String.valueOf(id), object.getString("name_de"), String.valueOf(level), "", "", ""));
}
public Node[] getNodes() {
assignParentIds();
assignNextIds();
assignChildIds();
Node[] nodeArr = new Node[nodes.size()];
for(int i = 0; i < nodes.size(); i++) {
nodeArr[i] = nodes.get(i);
}
return nodeArr;
}
private void assignParentIds() {
Map<String, Node> lastNodesWithHigherLevel = new HashMap<String, Node>();
for(Node node : nodes) {
Node higher = lastNodesWithHigherLevel.get(String.valueOf(Integer.valueOf(node.tlevel) - 1));
if(higher != null) {
node.parentid = higher.nodeid;
}
lastNodesWithHigherLevel.put(node.tlevel, node);
}
}
private void assignNextIds() {
Map<String, Node> lastNodeOnSameLevel = new HashMap<String, Node>();
for(Node node : nodes) {
Node last = lastNodeOnSameLevel.get(node.tlevel);
if(last != null) {
if(last.parentid.equals(node.parentid)) {
// If the last and this node have the same parent
last.nextid = node.nodeid;
}
}
lastNodeOnSameLevel.put(node.tlevel, node);
}
}
private void assignChildIds() {
Iterator<Node> parentIterator = nodes.iterator();
Iterator<Node> childIterator = nodes.iterator();
// Init child iterator one further
if(childIterator.hasNext()) {
childIterator.next();
}
do {
Node parent = parentIterator.next();
Node child = childIterator.next();
// If level of parent is higher (<) set the value
if(Integer.valueOf(parent.tlevel) < Integer.valueOf(child.tlevel)) {
parent.childid = child.nodeid;
}
} while (childIterator.hasNext());
// Because childIterator will first be done, but parentIterator might need one more reference, we need do while
}
private static class Node implements Serializable {
public String zshop, nodename, parentid, childid, nextid, nodeid, tlevel;
public Node(String zshop, String nodeid, String nodename, String tlevel, String parentid, String childid, String nextid) {
this.zshop = zshop;
this.nodeid = nodeid;
this.nodename = nodename;
this.tlevel = tlevel;
this.parentid = parentid;
this.childid = childid;
this.nextid = nextid;
}
@Override
public String toString() {
return "{zshop:" + zshop + ", nodename:" + nodename + ", parentid:" + parentid + ", childid:" + childid
+ ", nextid:" + nextid + ", nodeid:" + nodeid + ", tlevel:" + tlevel + "}";
}
}
}
그리고 흐름 구성 :
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:java="http://www.mulesoft.org/schema/mule/java" xmlns:ee="http://www.mulesoft.org/schema/mule/ee/core"
xmlns:file="http://www.mulesoft.org/schema/mule/file"
xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/file http://www.mulesoft.org/schema/mule/file/current/mule-file.xsd
http://www.mulesoft.org/schema/mule/ee/core http://www.mulesoft.org/schema/mule/ee/core/current/mule-ee.xsd
http://www.mulesoft.org/schema/mule/java http://www.mulesoft.org/schema/mule/java/current/mule-java.xsd">
<http:listener-config name="HTTP_Listener_config" doc:name="HTTP Listener config" doc:id="e31dc867-3f9f-457b-8013-cd50a74c0af1" >
<http:listener-connection host="0.0.0.0" port="8081" />
</http:listener-config>
<file:config name="File_Config" doc:name="File Config" doc:id="3279487e-61ca-4845-89a2-5332e7c02638" />
<flow name="java-flow" doc:id="3c036218-560d-44f0-aef5-0c7f0ef4d776" >
<http:listener doc:name="Listener" doc:id="265a1691-4f9b-40e2-a280-592daf719002" config-ref="HTTP_Listener_config" path="java">
<http:response >
<http:body ><![CDATA[#[output application/json ---
payload]]]></http:body>
</http:response>
</http:listener>
<file:read doc:name="Copy_of_Read" doc:id="9f8b3c6f-f674-45f7-80fe-756f64602b30" config-ref="File_Config" path="response.json" />
<set-variable doc:name="Set Variable" doc:id="ecff267b-3b73-45d1-924e-227a01a99e4e" variableName="Tree" value="#[null]" />
<java:new doc:name="New Tree" doc:id="764d60bf-da41-4f17-8e13-c8bf31f141dc" class="valion.Tree" constructor="Tree()" target="Tree" />
<foreach doc:name="For Each" doc:id="e612fd8b-636e-41c2-b603-e6861514306b" collection="#[payload.productGroups]">
<java:invoke doc:name="Traverse" doc:id="96da4743-00d3-4970-a9e5-712877bcf2a9" class="valion.Tree" instance="#[vars.Tree]" method="enter(java.lang.String,java.lang.Integer)">
<java:args><![CDATA[#[%dw 2.0
output application/java
---
{
jsonString: write( payload,'application/json'),
level: 1
}]]]></java:args>
</java:invoke>
</foreach>
<java:invoke doc:name="Get Nodes" doc:id="999d5f4c-80b4-4793-9188-e17725ad030b" instance="#[vars.Tree]" class="valion.Tree" method="getNodes()">
</java:invoke>
<ee:transform doc:name="Transform Message" doc:id="b078bef3-45aa-4821-b7d1-720c2c7d0580">
<ee:message>
<ee:set-payload><![CDATA[%dw 2.0
output application/json
---
{
hierarchieSet: payload map ( item , index ) -> {
zshop: item.zshop,
nodeid: item.nodeid,
nodename: item.nodename,
tlevel: item.tlevel,
parentid: item.parentid,
childid: item.childid,
nextid: item.nextid
}
}]]></ee:set-payload>
</ee:message>
</ee:transform>
</flow>
</mule>
