2012-03-27 6 views
28

क्या जैक्सन JSON लाइब्रेरी के साथ दो JSON दस्तावेज़ों को मर्ज करना संभव है? मैं मूल रूप से जैक्सन मैपर का उपयोग सरल जावा मैप्स के साथ कर रहा हूं।जैक्सन का उपयोग कर दो JSON दस्तावेज़ों को विलय करना

मैंने Google और जैक्सन के दस्तावेज़ों में खोज करने की कोशिश की है लेकिन कुछ भी नहीं मिला।

उत्तर

32

एक तरह से तो जैसे ObjectReader उपयोग करने के लिए है:

MyBean defaults = objectMapper.readValue(defaultJson, MyBean.class); 
ObjectReader updater = objectMapper.readerForUpdating(defaults); 
MyBean merged = updater.readValue(overridesJson); 

जो दो स्रोतों से डेटा जोड़ेगा। यह केवल एक उथली प्रतिलिपि बनाता है, यानी निहित वस्तुओं पर पुनरावर्ती विलय नहीं करता है।

अन्यथा आपको केवल एक पेड़ (JsonNode) के रूप में JSON को पढ़ने की आवश्यकता हो सकती है, सामग्री पर लूप और मैन्युअल रूप से विलय हो सकता है। यह अक्सर समझ में आता है क्योंकि विलय के नियम तुच्छ नहीं हैं, और हर किसी के पास अपने विचार हैं कि कैसे विलय करना चाहिए।

संपादित: (03-अप्रैल 2017)

प्रति @Fernando Correia की टिप्पणी के रूप में, वहाँ वास्तव में एक नया feature आगामी जैक्सन 2.9 में जोड़ा की अनुमति देने वाला (अप्रैल या मई 2017 में जारी होने की) अंत में गहरी विलय

+1

आपके उत्तर के लिए धन्यवाद। मुझे गहरी विलय की ज़रूरत है, इसलिए आप मर्ज लिखने के सुझाव हैं मैन्युअल रूप से मुझे लगता है कि जब मैंने प्रश्न पोस्ट किया था तो मुझे लगता था। मेरे अंतर्निहित डेटा संरचनाएं मानचित्र हैं, इसलिए जावा मानचित्रों के लिए एक सामान्य गहरी मर्ज दिनचर्या लिखना उचित होना चाहिए। यह कुछ भविष्य की परियोजना में पुनः उपयोग करने योग्य साबित हो सकता है। – Danish

+0

अब एक विशेषता के रूप में गहरा विलय उपलब्ध है? – yathirigan

+0

नहीं, जैक्सन 2.6 के रूप में नहीं। – StaxMan

47

StaxMans उत्तर से प्रेरित मैंने इस विलय विधि को लागू किया।

public static JsonNode merge(JsonNode mainNode, JsonNode updateNode) { 

    Iterator<String> fieldNames = updateNode.fieldNames(); 
    while (fieldNames.hasNext()) { 

     String fieldName = fieldNames.next(); 
     JsonNode jsonNode = mainNode.get(fieldName); 
     // if field exists and is an embedded object 
     if (jsonNode != null && jsonNode.isObject()) { 
      merge(jsonNode, updateNode.get(fieldName)); 
     } 
     else { 
      if (mainNode instanceof ObjectNode) { 
       // Overwrite field 
       JsonNode value = updateNode.get(fieldName); 
       ((ObjectNode) mainNode).put(fieldName, value); 
      } 
     } 

    } 

    return mainNode; 
} 

उम्मीद है कि यह किसी की सहायता करेगा।

+0

बहुत अच्छा लगता है @ अरन! अगर मुझे भविष्य की परियोजना में ऐसा करने की ज़रूरत है तो यह सहायक होगा। जब मैंने यह सवाल पूछा, तो मैं लोचदार खोज के साथ काम कर रहा था और मुझे इसके लिए आंशिक अपडेट प्लगइन मिला। इससे उस समय मेरी मदद मिली। – Danish

+3

उत्कृष्ट, अर्ने, यह वही है जो मुझे चाहिए, आपने मुझे जांच के घंटे बचाए हैं, धन्यवाद। जैक्सन 2.4 'डालने() 'के रूप में इसे' धन्यवाद 'टिप्पणी से थोड़ा अधिक बनाने के लिए इसे हटा दिया गया है और इसे' प्रतिस्थापन()' के साथ प्रतिस्थापित किया जाना चाहिए।इसके अलावा, जेडीके 8 उपयोगकर्ताओं के लिए, कोड को सीधे 'itEachRemaining()' के छोटे आवेदक के साथ और कुछ छोटे लैम्ब्डा-अभिव्यक्ति में गुजरने के मामूली आविष्कार के साथ अधिक संक्षेप में बनाया जा सकता है। – quantum

7

अरन के जवाब से प्रेरित। उस मामले को जोड़ने के लिए इसे संपादित करना जहां नोड में नोड्स की सरणी हो सकती है।

public static JsonNode merge(JsonNode mainNode, JsonNode updateNode) { 

    Iterator<String> fieldNames = updateNode.fieldNames(); 

    while (fieldNames.hasNext()) { 
     String updatedFieldName = fieldNames.next(); 
     JsonNode valueToBeUpdated = mainNode.get(updatedFieldName); 
     JsonNode updatedValue = updateNode.get(updatedFieldName); 

     // If the node is an @ArrayNode 
     if (valueToBeUpdated != null && valueToBeUpdated.isArray() && 
      updatedValue.isArray()) { 
      // running a loop for all elements of the updated ArrayNode 
      for (int i = 0; i < updatedValue.size(); i++) { 
       JsonNode updatedChildNode = updatedValue.get(i); 
       // Create a new Node in the node that should be updated, if there was no corresponding node in it 
       // Use-case - where the updateNode will have a new element in its Array 
       if (valueToBeUpdated.size() <= i) { 
        ((ArrayNode) valueToBeUpdated).add(updatedChildNode); 
       } 
       // getting reference for the node to be updated 
       JsonNode childNodeToBeUpdated = valueToBeUpdated.get(i); 
       merge(childNodeToBeUpdated, updatedChildNode); 
      } 
     // if the Node is an @ObjectNode 
     } else if (valueToBeUpdated != null && valueToBeUpdated.isObject()) { 
      merge(valueToBeUpdated, updatedValue); 
     } else { 
      if (mainNode instanceof ObjectNode) { 
       ((ObjectNode) mainNode).replace(updatedFieldName, updatedValue); 
      } 
     } 
    } 
    return mainNode; 
} 
+0

'valueToBeUpdated' का 'ArrayNode'' का कास्टिंग सुरक्षित नहीं है। उदाहरण के लिए, उस चर में 'ArrayNode' के बजाय, आप' टेक्स्ट नोड 'प्राप्त कर सकते हैं। – PNS

+0

धन्यवाद पीएनएस। मैंने अपना जवाब संपादित कर लिया है और यह जांचने के लिए शर्त जोड़ा है कि क्या valueToBeUpdated एक arrayNode है –

4

नीचे स्कैला में एक कार्यान्वयन है। स्रोत और लक्ष्य नोड अधिकतर कम्यूटिव होते हैं, सिवाय इसके कि जब कोई स्रोत स्रोत और लक्ष्य दोनों में मौजूद होता है।

ArrayNode arrayNode = objectMapper.createArrayNode(); 
arrayNode.add(firstJsonNode); 
arrayNode.add(secondJsonNode); 
arrayNode.add(thirdJsonNode); 

JsonNode root = JsonNodeFactory.instance.objectNode(); 
((ObjectNode) root).put("", arrayNode); 
System.out.println("merged array node #: " + root); 
1

कोई बस एक JsonNode में दो या अधिक JsonNode वस्तु को जोड़ने के लिए चाहता है, यह एक तरीका हो सकता है। उम्मीद है कि यह सहायक होगा :)

/** 
* Merge two JSON tree into one i.e mergedInTo. 
* 
* @param toBeMerged 
* @param mergedInTo 
*/ 
public static void merge(JsonNode toBeMerged, JsonNode mergedInTo) { 
    Iterator<Map.Entry<String, JsonNode>> incomingFieldsIterator = toBeMerged.fields(); 
    Iterator<Map.Entry<String, JsonNode>> mergedIterator = mergedInTo.fields(); 

    while (incomingFieldsIterator.hasNext()) { 
     Map.Entry<String, JsonNode> incomingEntry = incomingFieldsIterator.next(); 

     JsonNode subNode = incomingEntry.getValue(); 

     if (subNode.getNodeType().equals(JsonNodeType.OBJECT)) { 
      boolean isNewBlock = true; 
      mergedIterator = mergedInTo.fields(); 
      while (mergedIterator.hasNext()) { 
       Map.Entry<String, JsonNode> entry = mergedIterator.next(); 
       if (entry.getKey().equals(incomingEntry.getKey())) { 
        merge(incomingEntry.getValue(), entry.getValue()); 
        isNewBlock = false; 
       } 
      } 
      if (isNewBlock) { 
       ((ObjectNode) mergedInTo).replace(incomingEntry.getKey(), incomingEntry.getValue()); 
      } 
     } else if (subNode.getNodeType().equals(JsonNodeType.ARRAY)) { 
      boolean newEntry = true; 
      mergedIterator = mergedInTo.fields(); 
      while (mergedIterator.hasNext()) { 
       Map.Entry<String, JsonNode> entry = mergedIterator.next(); 
       if (entry.getKey().equals(incomingEntry.getKey())) { 
        updateArray(incomingEntry.getValue(), entry); 
        newEntry = false; 
       } 
      } 
      if (newEntry) { 
       ((ObjectNode) mergedInTo).replace(incomingEntry.getKey(), incomingEntry.getValue()); 
      } 
     } 
     ValueNode valueNode = null; 
     JsonNode incomingValueNode = incomingEntry.getValue(); 
     switch (subNode.getNodeType()) { 
      case STRING: 
       valueNode = new TextNode(incomingValueNode.textValue()); 
       break; 
      case NUMBER: 
       valueNode = new IntNode(incomingValueNode.intValue()); 
       break; 
      case BOOLEAN: 
       valueNode = BooleanNode.valueOf(incomingValueNode.booleanValue()); 
     } 
     if (valueNode != null) { 
      updateObject(mergedInTo, valueNode, incomingEntry); 
     } 
    } 
} 

private static void updateArray(JsonNode valueToBePlaced, Map.Entry<String, JsonNode> toBeMerged) { 
    toBeMerged.setValue(valueToBePlaced); 
} 

private static void updateObject(JsonNode mergeInTo, ValueNode valueToBePlaced, 
           Map.Entry<String, JsonNode> toBeMerged) { 
    boolean newEntry = true; 
    Iterator<Map.Entry<String, JsonNode>> mergedIterator = mergeInTo.fields(); 
    while (mergedIterator.hasNext()) { 
     Map.Entry<String, JsonNode> entry = mergedIterator.next(); 
     if (entry.getKey().equals(toBeMerged.getKey())) { 
      newEntry = false; 
      entry.setValue(valueToBePlaced); 
     } 
    } 
    if (newEntry) { 
     ((ObjectNode) mergeInTo).replace(toBeMerged.getKey(), toBeMerged.getValue()); 
    } 
} 
0

यहाँ, एक में दो JSON पेड़ विलय से भरा गया है:

def mergeYamlObjects(source: ObjectNode, target: ObjectNode, overwrite: Boolean = true): ObjectNode = { 
    if (target == null) 
     source 
    else if (source == null) 
     target 
    else { 
     val result = source.deepCopy 
     val fieldlist = source.fieldNames.asScala.toList ++ target.fieldNames.asScala.toList 
     for (item <- fieldlist) { 
     if (!(source has item)) { 
      result put(item, target get item) 
     } else { 
      if ((source get item).isValueNode) { 
      if (target has item) 
       if (overwrite) 
       result.put(item, target get item) 
      } else { 
      result.put(item, mergeYamlObjects(source.get(item).asInstanceOf[ObjectNode], 
       target.get(item).asInstanceOf[ObjectNode], overwrite = overwrite)) 
      } 
     } 
     } 
     result 
    } 
    }