blob: bc34b439580d51151b0671f5963ef8c9cbc73957 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Jens Lukowski/Innoopract - initial renaming/restructuring
* Angelo Zerr <angelo.zerr@gmail.com> - copied from org.eclipse.wst.xml.core.internal.document.XMLModelParser
* modified in order to process JSON Objects.
* Alina Marin <alina@mx1.ibm.com> - fixed some stuff to improve the synch between the editor and the model.
*******************************************************************************/
package org.eclipse.wst.json.core.internal.document;
import java.util.Iterator;
import org.eclipse.wst.json.core.document.IJSONArray;
import org.eclipse.wst.json.core.document.IJSONModel;
import org.eclipse.wst.json.core.document.IJSONNode;
import org.eclipse.wst.json.core.document.IJSONObject;
import org.eclipse.wst.json.core.document.IJSONPair;
import org.eclipse.wst.json.core.document.IJSONValue;
import org.eclipse.wst.json.core.regions.JSONRegionContexts;
import org.eclipse.wst.sse.core.internal.provisional.events.RegionChangedEvent;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegionList;
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList;
/**
* JSONModelParser
*/
public class JSONModelParser {
private JSONModelContext context = null;
private JSONModelImpl model = null;
/**
*/
protected JSONModelParser(JSONModelImpl model) {
super();
if (model != null) {
this.model = model;
}
}
/**
* changeAttrName method
*
*/
private void changeAttrName(IStructuredDocumentRegion flatNode,
ITextRegion region) {
int offset = flatNode.getStart();
if (offset < 0)
return;
JSONNodeImpl root = (JSONNodeImpl) this.context.getRootNode();
if (root == null)
return;
IJSONNode node = root.getNodeAt(offset);
if (node == null)
return;
if (node.getNodeType() != IJSONNode.PAIR_NODE) {
return;
}
JSONPairImpl pair = (JSONPairImpl) node;
String name = flatNode.getText(region);
pair.setName(name);
JSONObjectImpl parentObj = (JSONObjectImpl) node.getParentNode();
if (parentObj != null && parentObj.getParentOrPairNode() instanceof JSONPairImpl) {
JSONPairImpl parentPair = (JSONPairImpl) parentObj.getParentOrPairNode();
if (parentPair.getValue() != parentObj.getParentNode()) {
parentPair.setValue(parentObj);
}
}
}
private void changeAttrValue(IStructuredDocumentRegion flatNode,
ITextRegion region) {
int offset = flatNode.getStart();
if (offset < 0)
return;
JSONNodeImpl root = (JSONNodeImpl) this.context.getRootNode();
if (root == null)
return;
IJSONNode node = root.getNodeAt(offset);
if (node == null)
return;
JSONValueImpl value = (JSONValueImpl) createJSONValue(region.getType());
value.setStructuredDocumentRegion(flatNode);
if(node.getNodeType() == IJSONNode.PAIR_NODE) {
JSONPairImpl pair = (JSONPairImpl) node;
pair.updateValue(value);
} else if (node.getFirstStructuredDocumentRegion() != null && isJSONValue(node.getFirstStructuredDocumentRegion().getType())) {
JSONValueImpl oldValue = (JSONValueImpl) node;
oldValue.updateValue(value);
} else if (node instanceof JSONArrayImpl) {
if (value.getValueRegionType().equals(JSONRegionContexts.JSON_VALUE_BOOLEAN)
|| value.getValueRegionType().equals(JSONRegionContexts.JSON_VALUE_NULL)) {
// If the parent is a JSONArray insert the new JSONValue at
// the end of the structure
JSONArrayImpl array = (JSONArrayImpl) node;
node.insertBefore(value, null);
array.add(value);
JSONPairImpl ownerPair = (JSONPairImpl) array.getParentOrPairNode();
if (ownerPair.getValue() == null)
ownerPair.setValue(array);
else
ownerPair.updateValue(array);
}
}
}
/**
* changeRegion method
*
*/
void changeRegion(RegionChangedEvent change,
IStructuredDocumentRegion flatNode, ITextRegion region) {
if (flatNode == null || region == null)
return;
if (this.model.getDocument() == null)
return;
this.context = new JSONModelContext(this.model.getDocument());
// determine if change was whitespace only change
boolean isWhitespaceChange = false;
if (change.getText() != null && change.getText().length() > 0) {
isWhitespaceChange = Character.isWhitespace(change.getText()
.charAt(0));
} else if (change.getDeletedText() != null
&& change.getDeletedText().length() > 0) {
isWhitespaceChange = Character.isWhitespace(change.getDeletedText()
.charAt(0));
}
if (isWhitespaceChange)
return;
// optimize typical cases
String regionType = region.getType();
/*
* if (regionType == JSONRegionContexts.JSON_CONTENT || regionType ==
* JSONRegionContexts.JSON_COMMENT_TEXT || regionType ==
* JSONRegionContexts.JSON_CDATA_TEXT || regionType ==
* JSONRegionContexts.BLOCK_TEXT || isNestedContent(regionType)) {
* changeData(flatNode, region); } else
*/
if (regionType == JSONRegionContexts.JSON_OBJECT_KEY) {
changeAttrName(flatNode, region);
} else if (isJSONValue(regionType)) {
changeAttrValue(flatNode, region);
} else if(regionType == JSONRegionContexts.JSON_UNKNOWN) {
return;
}
// else if (regionType == JSONRegionContexts.JSON_TAG_ATTRIBUTE_VALUE) {
// if (isWhitespaceChange
// && (change.getOffset() >= flatNode.getStartOffset()
// + region.getTextEnd())) {
// // change is entirely in white-space
// return;
// }
// changeAttrValue(flatNode, region);
// } else if (regionType ==
// JSONRegionContexts.JSON_TAG_ATTRIBUTE_EQUALS) {
// if (isWhitespaceChange
// && (change.getOffset() >= flatNode.getStartOffset()
// + region.getTextEnd())) {
// // change is entirely in white-space
// return;
// }
// changeAttrEqual(flatNode, region);
// } else if (regionType == JSONRegionContexts.JSON_TAG_NAME
// || isNestedTagName(regionType)) {
// if (isWhitespaceChange
// && (change.getOffset() >= flatNode.getStartOffset()
// + region.getTextEnd())) {
// // change is entirely in white-space
// return;
// }
// changeTagName(flatNode, region);
// }
else {
changeStructuredDocumentRegion(flatNode);
}
}
/**
*/
private void changeStartObject(IStructuredDocumentRegion flatNode,
ITextRegionList newRegions, ITextRegionList oldRegions) {
int offset = flatNode.getStart();
if (offset < 0)
return; // error
JSONNodeImpl root = (JSONNodeImpl) this.context.getRootNode();
if (root == null)
return; // error
IJSONNode node = root.getNodeAt(offset);
if (node == null)
return; // error
if (node.getNodeType() != IJSONNode.OBJECT_NODE) {
changeStructuredDocumentRegion(flatNode);
return;
}
JSONObjectImpl element = (JSONObjectImpl) node;
// check if changes are only for attributes and close tag
boolean tagNameUnchanged = false;
if (newRegions != null) {
Iterator e = newRegions.iterator();
while (e.hasNext()) {
ITextRegion region = (ITextRegion) e.next();
String regionType = region.getType();
// if (regionType == JSONRegionContexts.JSON_TAG_ATTRIBUTE_NAME
// || regionType == JSONRegionContexts.JSON_TAG_ATTRIBUTE_EQUALS
// || regionType == JSONRegionContexts.JSON_TAG_ATTRIBUTE_VALUE)
// continue;
// if (regionType == JSONRegionContexts.JSON_TAG_CLOSE) {
// // change from empty tag may have impact on structure
// if (!element.isEmptyTag())
// continue;
// } else if (regionType == JSONRegionContexts.JSON_TAG_NAME
// || isNestedTagName(regionType)) {
// String oldTagName = element.getTagName();
// String newTagName = flatNode.getText(region);
// if (oldTagName != null && newTagName != null
// && oldTagName.equals(newTagName)) {
// // the tag name is unchanged
// tagNameUnchanged = true;
// continue;
// }
// }
// other region has changed
changeStructuredDocumentRegion(flatNode);
return;
}
}
// if (oldRegions != null) {
// Iterator e = oldRegions.iterator();
// while (e.hasNext()) {
// ITextRegion region = (ITextRegion) e.next();
// String regionType = region.getType();
// if (regionType == JSONRegionContexts.JSON_TAG_ATTRIBUTE_NAME
// || regionType == JSONRegionContexts.JSON_TAG_ATTRIBUTE_EQUALS
// || regionType == JSONRegionContexts.JSON_TAG_ATTRIBUTE_VALUE)
// continue;
// if (regionType == JSONRegionContexts.JSON_TAG_CLOSE) {
// // change from empty tag may have impact on structure
// if (!element.isEmptyTag())
// continue;
// } else if (regionType == JSONRegionContexts.JSON_TAG_NAME
// || isNestedTagName(regionType)) {
// // if new tag name is unchanged, it's OK
// if (tagNameUnchanged)
// continue;
// }
//
// // other region has changed
// changeStructuredDocumentRegion(flatNode);
// return;
// }
// }
// update attributes
ITextRegionList regions = flatNode.getRegions();
if (regions == null)
return; // error
// NamedNodeMap attributes = element.getAttributes();
// if (attributes == null)
// return; // error
//
// // first remove attributes
// int regionIndex = 0;
// int attrIndex = 0;
// AttrImpl attr = null;
// while (attrIndex < attributes.getLength()) {
// attr = (AttrImpl) attributes.item(attrIndex);
// if (attr == null) { // error
// attrIndex++;
// continue;
// }
// ITextRegion nameRegion = attr.getNameRegion();
// if (nameRegion == null) { // error
// element.removeAttributeNode(attr);
// continue;
// }
// boolean found = false;
// for (int i = regionIndex; i < regions.size(); i++) {
// ITextRegion region = regions.get(i);
// if (region == nameRegion) {
// regionIndex = i + 1; // next region
// found = true;
// break;
// }
// }
// if (found) {
// attrIndex++;
// } else {
// element.removeAttributeNode(attr);
// }
// }
//
// // insert or update attributes
// attrIndex = 0; // reset to first
// AttrImpl newAttr = null;
// ITextRegion oldValueRegion = null;
// Iterator e = regions.iterator();
// while (e.hasNext()) {
// ITextRegion region = (ITextRegion) e.next();
// String regionType = region.getType();
// if (regionType == JSONRegionContexts.JSON_TAG_ATTRIBUTE_NAME) {
// if (newAttr != null) {
// // insert deferred new attribute
// element.insertAttributeNode(newAttr, attrIndex++);
// newAttr = null;
// } else if (attr != null && oldValueRegion != null) {
// // notify existing attribute value removal
// attr.notifyValueChanged();
// }
//
// oldValueRegion = null;
// attr = (AttrImpl) attributes.item(attrIndex);
// if (attr != null && attr.getNameRegion() == region) {
// // existing attribute
// attrIndex++;
// // clear other regions
// oldValueRegion = attr.getValueRegion();
// attr.setEqualRegion(null);
// attr.setValueRegion(null);
// } else {
// String name = flatNode.getText(region);
// attr = (AttrImpl) this.model.getDocument().createAttribute(
// name);
// if (attr != null)
// attr.setNameRegion(region);
// // defer insertion of new attribute
// newAttr = attr;
// }
// } else if (regionType ==
// JSONRegionContexts.JSON_TAG_ATTRIBUTE_EQUALS) {
// if (attr != null) {
// attr.setEqualRegion(region);
// }
// } else if (regionType ==
// JSONRegionContexts.JSON_TAG_ATTRIBUTE_VALUE) {
// if (attr != null) {
// attr.setValueRegion(region);
// if (attr != newAttr && oldValueRegion != region) {
// // notify existing attribute value changed
// attr.notifyValueChanged();
// }
// oldValueRegion = null;
// attr = null;
// }
// }
// }
//
// if (newAttr != null) {
// // insert deferred new attribute
// element.appendAttributeNode(newAttr);
// } else if (attr != null && oldValueRegion != null) {
// // notify existing attribute value removal
// attr.notifyValueChanged();
// }
}
/**
* changeStructuredDocumentRegion method
*
*/
private void changeStructuredDocumentRegion(
IStructuredDocumentRegion flatNode) {
if (flatNode == null)
return;
if (this.model.getDocument() == null)
return;
setupContext(flatNode);
removeStructuredDocumentRegion(flatNode);
// make sure the parent is set to deepest level
// when end tag has been removed
this.context.setLast();
insertStructuredDocumentRegion(flatNode);
// cleanupText();
cleanupEndTag();
}
/**
* cleanupContext method
*/
private void cleanupEndTag() {
IJSONNode parent = this.context.getParentNode();
IJSONNode next = this.context.getNextNode();
while (parent != null) {
while (next != null) {
if (next.getNodeType() == IJSONNode.OBJECT_NODE) {
JSONObjectImpl element = (JSONObjectImpl) next;
// if (element.isEndTag()) {
// // floating end tag
// String tagName = element.getTagName();
// String rootName = getFindRootName(tagName);
// JSONObjectImpl start = (JSONObjectImpl) this.context
// .findStartTag(tagName, rootName);
// if (start != null) {
// insertEndTag(start);
// // move the end tag from 'element' to 'start'
// start.addEndTag(element);
// removeNode(element);
// parent = this.context.getParentNode();
// next = this.context.getNextNode();
// continue;
// }
// }
}
IJSONNode first = next.getFirstChild();
if (first != null) {
parent = next;
next = first;
this.context.setCurrentNode(next);
} else {
next = next.getNextSibling();
this.context.setCurrentNode(next);
}
}
// if (parent.getNodeType() == IJSONNode.OBJECT_NODE) {
// JSONObjectImpl element = (JSONObjectImpl) parent;
// if (!element.hasEndTag() && element.hasStartTag()
// && element.getNextSibling() == null) {
// String tagName = element.getTagName();
// JSONObjectImpl end = (JSONObjectImpl) this.context
// .findEndTag(tagName);
// if (end != null) {
// // move the end tag from 'end' to 'element'
// element.addEndTag(end);
// removeEndTag(end);
// this.context.setParentNode(parent); // reset context
// continue;
// }
// }
// }
next = parent.getNextSibling();
parent = parent.getParentNode();
if (next != null) {
this.context.setCurrentNode(next);
} else {
this.context.setParentNode(parent);
}
}
}
/**
*/
private void demoteNodes(IJSONNode root, IJSONNode newParent,
IJSONNode oldParent, IJSONNode next) {
if (newParent.getNodeType() != IJSONNode.OBJECT_NODE)
return;
JSONObjectImpl newElement = (JSONObjectImpl) newParent;
// find next
while (next == null) {
if (oldParent.getNodeType() != IJSONNode.OBJECT_NODE)
return;
JSONObjectImpl oldElement = (JSONObjectImpl) oldParent;
if (oldElement.hasEndTag())
return;
oldParent = oldElement.getParentNode();
if (oldParent == null)
return; // error
next = oldElement.getNextSibling();
}
while (next != null) {
boolean done = false;
if (next.getNodeType() == IJSONNode.OBJECT_NODE) {
JSONObjectImpl nextElement = (JSONObjectImpl) next;
if (!nextElement.hasStartTag()) {
IJSONNode nextChild = nextElement.getFirstChild();
if (nextChild != null) {
// demote children
next = nextChild;
oldParent = nextElement;
continue;
}
// if (nextElement.hasEndTag()) {
// if (nextElement.matchEndTag(newElement)) {
// // stop at the matched invalid end tag
// next = nextElement.getNextSibling();
// oldParent.removeChild(nextElement);
// newElement.addEndTag(nextElement);
//
// if (newElement == root)
// return;
// IJSONNode p = newElement.getParentNode();
// // check if reached to top
// if (p == null || p == oldParent
// || p.getNodeType() != IJSONNode.OBJECT_NODE)
// return;
// newElement = (JSONObjectImpl) p;
// done = true;
// }
// } else {
// remove implicit element
next = nextElement.getNextSibling();
oldParent.removeChild(nextElement);
done = true;
// }
}
}
if (!done) {
// if (!canContain(newElement, next)) {
// if (newElement == root)
// return;
// Node p = newElement.getParentNode();
// // check if reached to top
// if (p == null || p == oldParent
// || p.getNodeType() != IJSONNode.OBJECT_NODE)
// return;
// newElement = (JSONObjectImpl) p;
// continue;
// }
IJSONNode child = next;
next = next.getNextSibling();
oldParent.removeChild(child);
insertNode(newElement, child, null);
IJSONNode childParent = child.getParentNode();
if (childParent != newElement) {
newElement = (JSONObjectImpl) childParent;
}
}
// find next parent and sibling
while (next == null) {
if (oldParent.getNodeType() != IJSONNode.OBJECT_NODE)
return;
JSONObjectImpl oldElement = (JSONObjectImpl) oldParent;
// dug parent must not have children at this point
if (!oldElement.hasChildNodes() && !oldElement.hasStartTag()) {
oldParent = oldElement.getParentNode();
if (oldParent == null)
return; // error
next = oldElement;
break;
}
if (oldElement.hasEndTag())
return;
oldParent = oldElement.getParentNode();
if (oldParent == null)
return; // error
next = oldElement.getNextSibling();
}
}
}
/**
*/
protected final IJSONModel getModel() {
return this.model;
}
/**
* insertEndTag method
*
*/
private void updateEndObject(IStructuredDocumentRegion flatNode) {
// ITextRegionList regions = flatNode.getRegions();
// if (regions == null)
// return;
//
// String tagName = null;
// Iterator e = regions.iterator();
// while (e.hasNext()) {
// ITextRegion region = (ITextRegion) e.next();
// String regionType = region.getType();
// if (regionType == JSONRegionContexts.JSON_TAG_NAME
// || isNestedTagName(regionType)) {
// if (tagName == null)
// tagName = flatNode.getText(region);
// }
// }
//
// if (tagName == null) { // invalid end tag
// insertText(flatNode); // regard as invalid text
// return;
// }
//
// String rootName = getFindRootName(tagName);
JSONObjectImpl start = (JSONObjectImpl) this.context
.findParentObject();
if (start != null) { // start tag found
// insertEndTag(start);
start.setEndStructuredDocumentRegion(flatNode);
// update context
this.context.setParentNode(start.getParentNode());
// // re-check the next sibling
// newNext = start.getNextSibling();
// if (newNext != null)
// this.context.setCurrentNode(newNext);
// else
// this.context.setParentNode(newParent);
// return;
}
//
// // invalid end tag
// JSONObjectImpl end = null;
// try {
// end = (JSONObjectImpl)
// this.model.getDocument().createElement(tagName);
// } catch (JSONException ex) {
// }
// if (end == null) { // invalid end tag
// insertText(flatNode); // regard as invalid text
// return;
// }
// end.setEndStructuredDocumentRegion(flatNode);
// insertNode(end);
}
/**
* insertNode method
*
* @param child
* org.w3c.dom.Node
*/
private void insertNode(IJSONNode node) {
if (node == null || this.context == null) {
return;
}
IJSONNode parent = this.context.getParentNode();
if (parent == null) {
return;
}
if (parent.getNodeType() == IJSONNode.PAIR_NODE) {
IJSONPair pair = (IJSONPair) parent;
((JSONPairImpl) pair).setValue((IJSONValue) node);
return;
}
if (parent.getLastChild() != null
&& parent.getLastChild().getNodeType() == IJSONNode.PAIR_NODE) {
IJSONPair pair = (IJSONPair) parent.getLastChild();
((JSONPairImpl) pair).setValue((IJSONValue) node);
return;
}
IJSONNode next = this.context.getNextNode();
insertNode(parent, node, next);
next = node.getNextSibling();
if (next != null) {
this.context.setCurrentNode(next);
} else {
this.context.setParentNode(node.getParentNode());
}
// if (node != null && this.context != null) {
// IJSONNode aparent = this.context.getParentNode();
// if (parent != null) {
// IJSONNode next = this.context.getNextNode();
// // Reset parents which are closed container elements; should not
// // be parents
// if (parent.getNodeType() == IJSONNode.OBJECT_NODE) {
// String type = ((JSONObjectImpl) parent)
// .getStartStructuredDocumentRegion().getLastRegion()
// .getType();
// if (((JSONObjectImpl) parent).isContainer()
// /* && type == JSONRegionContexts.JSON_EMPTY_TAG_CLOSE */) {
// // next = parent.getNextSibling();
// // parent = parent.getParentNode();
// } else {
// // ModelParserAdapter adapter = getParserAdapter();
// // if (adapter != null) {
// // while (parent.getNodeType() == IJSONNode.OBJECT_NODE
// // && !adapter.canContain((Element) parent,
// // node)
// // && adapter
// // .isEndTagOmissible((Element) parent)) {
// // next = parent.getNextSibling();
// // parent = parent.getParentNode();
// // }
// // }
// }
// }
// insertNode(parent, node, next);
// next = node.getNextSibling();
// if (next != null) {
// this.context.setCurrentNode(next);
// } else {
// this.context.setParentNode(node.getParentNode());
// }
// }
// }
}
/**
*/
private void insertNode(IJSONNode parent, IJSONNode node, IJSONNode next) {
while (next != null && next.getNodeType() == IJSONNode.OBJECT_NODE) {
JSONObjectImpl nextElement = (JSONObjectImpl) next;
if (nextElement.hasStartTag())
break;
// if (!canBeImplicitTag(nextElement, node))
// break;
parent = nextElement;
next = nextElement.getFirstChild();
}
// Element implicitElement = createImplicitElement(parent, node);
// if (implicitElement != null)
// node = implicitElement;
parent.insertBefore(node, next);
}
private void insertObject(IStructuredDocumentRegion flatNode) {
ITextRegionList regions = flatNode.getRegions();
if (regions == null)
return;
JSONObjectImpl element = null;
if(this.context.getCurrentNode() != null && this.context.getCurrentNode() instanceof IJSONObject) {
element = (JSONObjectImpl) this.context.getCurrentNode();
} else {
element = (JSONObjectImpl) this.model.getDocument()
.createJSONObject();
}
if (element == null) {
return;
}
element.setStartStructuredDocumentRegion(flatNode);
insertStartObjectOLD(element);
}
protected void insertStartObjectOLD(IJSONObject element) {
if (element == null)
return;
if (this.context == null)
return;
insertNode(element);
JSONObjectImpl newElement = (JSONObjectImpl) element;
if (newElement.isEmptyTag() || !newElement.isContainer())
return;
// Ignore container tags that have been closed
String type = newElement.getStartStructuredDocumentRegion()
.getLastRegion().getType();
// if (newElement.isContainer()
// && type == JSONRegionContexts.JSON_EMPTY_TAG_CLOSE)
// return;
// demote siblings
IJSONNode parent = this.context.getParentNode();
if (parent == null)
return; // error
IJSONNode next = this.context.getNextNode();
demoteNodes(element, element, parent, next);
// update context
IJSONNode firstChild = element.getFirstChild();
if (firstChild != null)
this.context.setCurrentNode(firstChild);
else
this.context.setParentNode(element);
}
// ---------------------------- JSON Array
protected void insertStartArray(IJSONArray element) {
if (element == null)
return;
if (this.context == null)
return;
insertNode(element);
JSONArrayImpl newElement = (JSONArrayImpl) element;
String type = newElement.getStartStructuredDocumentRegion()
.getLastRegion().getType();
// demote siblings
IJSONNode parent = this.context.getParentNode();
if (parent == null)
return; // error
IJSONNode next = this.context.getNextNode();
demoteNodes(element, element, parent, next);
// update context
IJSONNode firstChild = element.getFirstChild();
if (firstChild != null)
this.context.setCurrentNode(firstChild);
else
this.context.setParentNode(element);
}
/**
* insertStartTag method
*
*/
private void insertArray(IStructuredDocumentRegion flatNode) {
ITextRegionList regions = flatNode.getRegions();
if (regions == null)
return;
JSONArrayImpl element = (JSONArrayImpl) this.model.getDocument()
.createJSONArray();
element.setStartStructuredDocumentRegion(flatNode);
insertStartArray(element);
}
private void updateEndArray(IStructuredDocumentRegion flatNode) {
JSONArrayImpl start = (JSONArrayImpl) this.context.findParentArray();
if (start != null) { // start tag found
start.setEndStructuredDocumentRegion(flatNode);
// update context
this.context.setParentNode(start.getParentNode());
}
}
// ---------------- Commons insert
/**
* insertStructuredDocumentRegion method
*
*/
protected void insertStructuredDocumentRegion(
IStructuredDocumentRegion flatNode) {
String regionType = StructuredDocumentRegionUtil
.getFirstRegionType(flatNode);
if (regionType == JSONRegionContexts.JSON_OBJECT_OPEN) {
insertObject(flatNode);
} else if (regionType == JSONRegionContexts.JSON_OBJECT_CLOSE) {
updateEndObject(flatNode);
} else if (regionType == JSONRegionContexts.JSON_ARRAY_OPEN) {
insertArray(flatNode);
} else if (regionType == JSONRegionContexts.JSON_ARRAY_CLOSE) {
updateEndArray(flatNode);
} else if (regionType == JSONRegionContexts.JSON_OBJECT_KEY) {
insertObjectKey(flatNode);
} else if (regionType == JSONRegionContexts.JSON_VALUE_BOOLEAN) {
insertValue(flatNode, regionType);
} else if (regionType == JSONRegionContexts.JSON_VALUE_NULL) {
insertValue(flatNode, regionType);
} else if (regionType == JSONRegionContexts.JSON_VALUE_NUMBER) {
insertValue(flatNode, regionType);
} else if (regionType == JSONRegionContexts.JSON_VALUE_STRING) {
insertValue(flatNode, regionType);
}
}
private void insertValue(IStructuredDocumentRegion flatNode,
String regionType) {
ITextRegionList regions = flatNode.getRegions();
if (regions == null)
return;
ITextRegion nameRegion = StructuredDocumentRegionUtil
.getFirstRegion(flatNode);
// Create JSON Value
JSONValueImpl value = (JSONValueImpl) createJSONValue(regionType);
value.setStructuredDocumentRegion(flatNode);
// If current node is different from null, it means this value shoyld be
// inserted as the value of an existing pair node
if (this.context.getCurrentNode() != null && this.context.getCurrentNode() instanceof JSONPairImpl) {
JSONPairImpl pair = (JSONPairImpl) this.context.getCurrentNode();
pair.setValue(value);
JSONNodeImpl parent = (JSONNodeImpl) this.context.getParentNode();
parent.insertBefore(pair, this.context.getNextNode());
// If parent is an instance of JSONObject add the pair node to the
// parent node
if(parent instanceof IJSONObject) {
JSONObjectImpl parentObject = (JSONObjectImpl) parent;
parentObject.add(pair);
}
} else {
// There is no context, it means the model is reloaded or loaded for
// the first time
JSONStructureImpl structure = (JSONStructureImpl) this.context.findParentStructure();
if (structure != null) {
if (structure.getNodeType() == IJSONNode.OBJECT_NODE) {
// If the parent is a JSONObject look for the last children,
// ensure it is a JSONPair and add set the value of the last
// children
if (structure.getLastChild() != null
&& structure.getLastChild().getNodeType() == IJSONNode.PAIR_NODE) {
((JSONPairImpl) structure.getLastChild()).setValue(value);
}
if(structure.getParentOrPairNode() instanceof JSONPairImpl) {
JSONPairImpl parentPair = (JSONPairImpl) structure.getParentOrPairNode();
if (structure.getParentNode() != parentPair.getValue()) {
parentPair.setValue(structure);
}
}
} else if (structure.getNodeType() == IJSONNode.ARRAY_NODE) {
// If the parent is a JSONArray insert the new JSONValue at
// the end of the structure
JSONArrayImpl array = (JSONArrayImpl) structure;
structure.insertBefore(value, null);
array.add(value);
JSONPairImpl ownerPair = (JSONPairImpl) array.getParentOrPairNode();
if(ownerPair.getValue() == null)
ownerPair.setValue(array);
else
ownerPair.updateValue(array);
} else {
insertNode(structure, value, null);
}
}
}
}
private IJSONValue createJSONValue(String regionType) {
if (regionType == JSONRegionContexts.JSON_VALUE_BOOLEAN) {
return this.model.getDocument().createBooleanValue();
} else if (regionType == JSONRegionContexts.JSON_VALUE_NULL) {
return this.model.getDocument().createNullValue();
} else if (regionType == JSONRegionContexts.JSON_VALUE_NUMBER) {
return this.model.getDocument().createNumberValue();
} else if (regionType == JSONRegionContexts.JSON_VALUE_STRING) {
return this.model.getDocument().createStringValue();
}
return null;
}
private void insertNumberValue(IStructuredDocumentRegion flatNode) {
ITextRegionList regions = flatNode.getRegions();
if (regions == null)
return;
ITextRegion nameRegion = StructuredDocumentRegionUtil
.getFirstRegion(flatNode);
JSONStructureImpl array = (JSONStructureImpl) this.context
.findParentStructure();
if (array != null) {
JSONNumberValueImpl value = (JSONNumberValueImpl) this.model
.getDocument().createNumberValue();
insertNode(array, value, null);
}
}
private void insertNullValue(IStructuredDocumentRegion flatNode) {
ITextRegionList regions = flatNode.getRegions();
if (regions == null)
return;
ITextRegion nameRegion = StructuredDocumentRegionUtil
.getFirstRegion(flatNode);
JSONStructureImpl array = (JSONStructureImpl) this.context
.findParentStructure();
if (array != null) {
JSONNullValueImpl value = (JSONNullValueImpl) this.model
.getDocument().createNullValue();
insertNode(array, value, null);
}
}
private void insertStringValue(IStructuredDocumentRegion flatNode) {
ITextRegionList regions = flatNode.getRegions();
if (regions == null)
return;
ITextRegion nameRegion = StructuredDocumentRegionUtil
.getFirstRegion(flatNode);
JSONStructureImpl array = (JSONStructureImpl) this.context
.findParentStructure();
if (array != null) {
JSONStringValueImpl value = (JSONStringValueImpl) this.model
.getDocument().createStringValue();
insertNode(array, value, null);
}
}
private void insertObjectKey(IStructuredDocumentRegion flatNode) {
ITextRegionList regions = flatNode.getRegions();
if (regions == null) {
return;
}
JSONObjectImpl object = (JSONObjectImpl) this.context
.findParentObject();
if (object == null) {
return;
}
JSONPairImpl pair = null;
for (Iterator i = regions.iterator(); i.hasNext();) {
ITextRegion region = (ITextRegion) i.next();
if (region == null) {
continue;
}
if (region.getType() == JSONRegionContexts.JSON_OBJECT_KEY) {
// Set the proper name and region to the JSONPair node
String name = flatNode.getText(region);
pair = (JSONPairImpl) this.model.getDocument().createJSONPair(name);
pair.setStartStructuredDocumentRegion(flatNode);
pair.setNameRegion(region);
// Ensure to add the pair node in the right place, taking as
// reference the current node offset from the context
if (context.getCurrentNode() != null
&& context.getCurrentNode().getStartOffset() > pair.getStartOffset())
insertNode(object, pair, this.context.getCurrentNode());
else
insertNode(object, pair, this.context.getNextNode());
// Add the pair to the parent object
object.add(pair);
// Update context with the new JSONPair as the current node
if (this.context.getCurrentNode() != null
&& this.context.getCurrentNode().getStartOffset() == pair.getStartOffset())
this.context.setCurrentNode(pair);
if(object.getParentOrPairNode() instanceof JSONPairImpl) {
JSONPairImpl parentPair = (JSONPairImpl) object.getParentOrPairNode();
if (object.getParentNode() != parentPair.getValue()) {
parentPair.setValue(object);
}
}
} else if (region.getType() == JSONRegionContexts.JSON_COLON) {
pair.setEqualRegion(region);
} else if (region.getType() == JSONRegionContexts.JSON_VALUE_BOOLEAN) {
JSONBooleanValueImpl value = (JSONBooleanValueImpl) this.model
.getDocument().createBooleanValue();
pair.setValue(value);
} else if (region.getType() == JSONRegionContexts.JSON_VALUE_NULL) {
JSONNullValueImpl value = (JSONNullValueImpl) this.model
.getDocument().createNullValue();
pair.setValue(value);
} else if (region.getType() == JSONRegionContexts.JSON_VALUE_NUMBER) {
JSONNumberValueImpl value = (JSONNumberValueImpl) this.model
.getDocument().createNumberValue();
pair.setValue(value);
} else if (region.getType() == JSONRegionContexts.JSON_VALUE_STRING) {
JSONStringValueImpl value = (JSONStringValueImpl) this.model
.getDocument().createStringValue();
pair.setValue(value);
}
}
}
protected boolean isNestedTag(String regionType) {
boolean result = false;
return result;
}
protected boolean isNestedCommentText(String regionType) {
boolean result = false;
return result;
}
protected boolean isNestedCommentOpen(String regionType) {
boolean result = false;
return result;
}
protected boolean isNestedTagName(String regionType) {
boolean result = false;
return result;
}
protected boolean isNestedContent(String regionType) {
boolean result = false;
return result;
}
/**
*/
private void promoteNodes(IJSONNode root, IJSONNode newParent,
IJSONNode newNext, IJSONNode oldParent, IJSONNode next) {
JSONObjectImpl newElement = null;
if (newParent.getNodeType() == IJSONNode.OBJECT_NODE) {
newElement = (JSONObjectImpl) newParent;
}
IJSONNode rootParent = root.getParentNode();
while (oldParent != rootParent) {
while (next != null) {
boolean done = false;
boolean endTag = false;
if (next.getNodeType() == IJSONNode.OBJECT_NODE) {
JSONObjectImpl nextElement = (JSONObjectImpl) next;
if (!nextElement.hasStartTag()) {
IJSONNode nextChild = nextElement.getFirstChild();
if (nextChild != null) {
// promote children
next = nextChild;
oldParent = nextElement;
continue;
}
// if (nextElement.hasEndTag()) {
// if (nextElement.matchEndTag(newElement)) {
// endTag = true;
// }
// } else {
// remove implicit element
next = nextElement.getNextSibling();
oldParent.removeChild(nextElement);
done = true;
// }
}
}
if (!done) {
if (!endTag && newElement != null
/* && !canContain(newElement, next) */) {
newParent = newElement.getParentNode();
if (newParent == null)
return; // error
IJSONNode elementNext = newElement.getNextSibling();
// promote siblings
promoteNodes(newElement, newParent, elementNext,
newElement, newNext);
newNext = newElement.getNextSibling();
if (newParent.getNodeType() == IJSONNode.OBJECT_NODE) {
newElement = (JSONObjectImpl) newParent;
} else {
newElement = null;
}
continue;
}
IJSONNode child = next;
next = next.getNextSibling();
oldParent.removeChild(child);
insertNode(newParent, child, newNext);
IJSONNode childParent = child.getParentNode();
if (childParent != newParent) {
newParent = childParent;
newElement = (JSONObjectImpl) newParent;
newNext = child.getNextSibling();
}
}
}
if (oldParent.getNodeType() != IJSONNode.OBJECT_NODE)
return;
JSONObjectImpl oldElement = (JSONObjectImpl) oldParent;
oldParent = oldElement.getParentNode();
if (oldParent == null)
return; // error
next = oldElement.getNextSibling();
if (oldElement.hasEndTag()) {
IJSONObject end = null;
if (!oldElement.hasChildNodes() && !oldElement.hasStartTag()) {
oldParent.removeChild(oldElement);
end = oldElement;
} else {
// end = oldElement.removeEndTag();
}
if (end != null) {
insertNode(newParent, end, newNext);
IJSONNode endParent = end.getParentNode();
if (endParent != newParent) {
newParent = endParent;
newElement = (JSONObjectImpl) newParent;
newNext = end.getNextSibling();
}
}
}
}
}
/**
* removeEndTag method
*
* @param element
* org.w3c.dom.Element
*/
private void removeEndTag(IJSONNode element) {
if (element == null)
return;
if (this.context == null)
return;
IJSONNode parent = element.getParentNode();
if (parent == null)
return; // error
if (!((JSONObjectImpl) element).isContainer()) {
// just update context
IJSONNode elementNext = element.getNextSibling();
if (elementNext != null)
this.context.setCurrentNode(elementNext);
else
this.context.setParentNode(parent);
return;
}
// demote siblings
IJSONNode next = element.getNextSibling();
JSONObjectImpl newElement = (JSONObjectImpl) element;
// find new parent
for (IJSONNode last = newElement.getLastChild(); last != null; last = last
.getLastChild()) {
if (last.getNodeType() != IJSONNode.OBJECT_NODE)
break;
JSONObjectImpl lastElement = (JSONObjectImpl) last;
if (lastElement.hasEndTag() || lastElement.isEmptyTag()
|| !lastElement.isContainer())
break;
newElement = lastElement;
}
IJSONNode lastChild = newElement.getLastChild();
demoteNodes(element, newElement, parent, next);
// update context
IJSONNode newNext = null;
if (lastChild != null)
newNext = lastChild.getNextSibling();
else
newNext = newElement.getFirstChild();
if (newNext != null)
this.context.setCurrentNode(newNext);
else
this.context.setParentNode(newElement);
}
/**
* removeNode method
*
* @param node
* org.w3c.dom.Node
*/
private void removeNode(IJSONNode node) {
if (node == null)
return;
if (this.context == null)
return;
IJSONNode parent = node.getParentNode();
if (parent == null) {
if(node instanceof IJSONValue) {
parent = node.getParentOrPairNode();
if(parent == null) {
return;
}
}
}
IJSONNode next = node.getNextSibling();
IJSONNode prev = node.getPreviousSibling();
// update context
IJSONNode oldParent = this.context.getParentNode();
if (node == oldParent) {
if (next != null)
this.context.setCurrentNode(next);
else
this.context.setParentNode(parent);
} else {
IJSONNode oldNext = this.context.getNextNode();
if (node == oldNext) {
this.context.setCurrentNode(next);
}
}
parent.removeChild(node);
// if (removeImplicitElement(parent) != null)
// return;
// demote sibling
if (prev != null && prev.getNodeType() == IJSONNode.OBJECT_NODE) {
JSONObjectImpl newElement = (JSONObjectImpl) prev;
if (!newElement.hasEndTag() && !newElement.isEmptyTag()
&& newElement.isContainer()) {
// find new parent
for (IJSONNode last = newElement.getLastChild(); last != null; last = last
.getLastChild()) {
if (last.getNodeType() != IJSONNode.OBJECT_NODE)
break;
JSONObjectImpl lastElement = (JSONObjectImpl) last;
if (lastElement.hasEndTag() || lastElement.isEmptyTag()
|| !lastElement.isContainer())
break;
newElement = lastElement;
}
IJSONNode lastChild = newElement.getLastChild();
demoteNodes(prev, newElement, parent, next);
// update context
IJSONNode newNext = null;
if (lastChild != null)
newNext = lastChild.getNextSibling();
else
newNext = newElement.getFirstChild();
if (newNext != null)
this.context.setCurrentNode(newNext);
else
this.context.setParentNode(newElement);
}
}
}
/**
* removeStartTag method
*
* @param element
* org.w3c.dom.Element
*/
private void removeStartObject(IJSONObject element) {
if (element == null)
return;
if (this.context == null)
return;
// for implicit tag
JSONObjectImpl oldElement = (JSONObjectImpl) element;
// if (canBeImplicitTag(oldElement)) {
// Node newParent = null;
// Node prev = oldElement.getPreviousSibling();
// if (prev != null && prev.getNodeType() == IJSONNode.OBJECT_NODE) {
// JSONObjectImpl prevElement = (JSONObjectImpl) prev;
// if (!prevElement.hasEndTag()) {
// if (prevElement.hasStartTag()
// || prevElement
// .matchTagName(oldElement.getTagName())) {
// newParent = prevElement;
// }
// }
// }
// if (newParent == null) {
// // this element should stay as implicit tag
// // just remove all attributes
// oldElement.removeStartTag();
//
// // update context
// Node child = oldElement.getFirstChild();
// if (child != null) {
// this.context.setCurrentNode(child);
// } else if (oldElement.hasEndTag()) {
// this.context.setParentNode(oldElement);
// }
// return;
// }
// }
// // for comment tag
// if (oldElement.isCommentTag())
// oldElement.removeStartTag();
// promote children
IJSONNode elementParent = element.getParentNode();
IJSONNode parent = elementParent;
if (parent == null)
return;
IJSONNode first = element.getFirstChild();
IJSONNode firstElement = null; // for the case first is removed as end
// tag
if (first != null) {
// find new parent for children
JSONObjectImpl newElement = null;
for (IJSONNode last = element.getPreviousSibling(); last != null; last = last
.getLastChild()) {
if (last.getNodeType() != IJSONNode.OBJECT_NODE)
break;
JSONObjectImpl lastElement = (JSONObjectImpl) last;
if (lastElement.hasEndTag() || lastElement.isEmptyTag()
|| !lastElement.isContainer())
break;
newElement = lastElement;
}
IJSONNode next = first;
if (newElement != null) {
while (next != null) {
if (!newElement.hasEndTag() && newElement.hasStartTag()
&& next.getNodeType() == IJSONNode.OBJECT_NODE) {
JSONObjectImpl nextElement = (JSONObjectImpl) next;
if (!nextElement.hasStartTag()
&& nextElement.hasEndTag()
/* && nextElement.matchEndTag(newElement) */) {
// stop at the matched invalid end tag
IJSONNode elementChild = nextElement
.getFirstChild();
while (elementChild != null) {
IJSONNode nextChild = elementChild
.getNextSibling();
nextElement.removeChild(elementChild);
newElement.appendChild(elementChild);
elementChild = nextChild;
}
next = nextElement.getNextSibling();
element.removeChild(nextElement);
// newElement.addEndTag(nextElement);
if (nextElement == first)
firstElement = newElement;
IJSONNode newParent = newElement.getParentNode();
if (newParent == parent)
break;
if (newParent == null
|| newParent.getNodeType() != IJSONNode.OBJECT_NODE)
break; // error
newElement = (JSONObjectImpl) newParent;
continue;
}
}
// if (!canContain(newElement, next)) {
// Node newParent = newElement.getParentNode();
// if (newParent == parent)
// break;
// if (newParent == null
// || newParent.getNodeType() != IJSONNode.OBJECT_NODE)
// break; // error
// newElement = (JSONObjectImpl) newParent;
// continue;
// }
IJSONNode child = next;
next = next.getNextSibling();
element.removeChild(child);
newElement.appendChild(child);
}
newElement = null;
}
if (parent.getNodeType() == IJSONNode.OBJECT_NODE) {
newElement = (JSONObjectImpl) parent;
}
while (next != null) {
if (newElement == null /* || canContain(newElement, next) */) {
IJSONNode child = next;
next = next.getNextSibling();
element.removeChild(child);
parent.insertBefore(child, element);
continue;
}
parent = newElement.getParentNode();
if (parent == null)
return;
// promote siblings
IJSONNode newNext = newElement.getNextSibling();
IJSONNode child = element;
while (child != null) {
IJSONNode nextChild = child.getNextSibling();
newElement.removeChild(child);
parent.insertBefore(child, newNext);
child = nextChild;
}
// leave the old end tag where it is
if (newElement.hasEndTag()) {
// IJSONObject end = newElement.removeEndTag();
// if (end != null) {
// parent.insertBefore(end, newNext);
// }
}
if (!newElement.hasStartTag()) {
// implicit element
if (!newElement.hasChildNodes()) {
parent.removeChild(newElement);
}
}
if (parent.getNodeType() == IJSONNode.OBJECT_NODE) {
newElement = (JSONObjectImpl) parent;
} else {
newElement = null;
}
}
}
IJSONNode newNext = element;
IJSONNode startElement = null; // for the case element is removed as end
// tag
if (oldElement.hasEndTag()) {
// find new parent for invalid end tag and siblings
JSONObjectImpl newElement = null;
for (IJSONNode last = element.getPreviousSibling(); last != null; last = last
.getLastChild()) {
if (last.getNodeType() != IJSONNode.OBJECT_NODE)
break;
JSONObjectImpl lastElement = (JSONObjectImpl) last;
if (lastElement.hasEndTag() || lastElement.isEmptyTag()
|| !lastElement.isContainer())
break;
newElement = lastElement;
}
if (newElement != null) {
// demote invalid end tag and sibling
IJSONNode next = element;
while (next != null) {
if (!newElement.hasEndTag() && newElement.hasStartTag()
&& next.getNodeType() == IJSONNode.OBJECT_NODE) {
JSONObjectImpl nextElement = (JSONObjectImpl) next;
if (!nextElement.hasStartTag()
&& nextElement.hasEndTag()
/* && nextElement.matchEndTag(newElement) */) {
// stop at the matched invalid end tag
IJSONNode elementChild = nextElement
.getFirstChild();
while (elementChild != null) {
IJSONNode nextChild = elementChild
.getNextSibling();
nextElement.removeChild(elementChild);
newElement.appendChild(elementChild);
elementChild = nextChild;
}
next = nextElement.getNextSibling();
parent.removeChild(nextElement);
// newElement.addEndTag(nextElement);
if (nextElement == newNext)
startElement = newElement;
IJSONNode newParent = newElement.getParentNode();
if (newParent == parent)
break;
if (newParent == null
|| newParent.getNodeType() != IJSONNode.OBJECT_NODE)
break; // error
newElement = (JSONObjectImpl) newParent;
continue;
}
}
// if (!canContain(newElement, next)) {
// Node newParent = newElement.getParentNode();
// if (newParent == parent)
// break;
// if (newParent == null
// || newParent.getNodeType() != IJSONNode.OBJECT_NODE)
// break; // error
// newElement = (JSONObjectImpl) newParent;
// continue;
// }
IJSONNode child = next;
next = next.getNextSibling();
parent.removeChild(child);
if (child == oldElement) {
// if (!oldElement.isCommentTag()) {
// clone (re-create) end tag
// IJSONObject end = oldElement.removeEndTag();
// if (end != null) {
// child = end;
// newNext = end;
// }
// }
}
newElement.appendChild(child);
}
} else {
// if (!oldElement.isCommentTag()) {
// clone (re-create) end tag
// IJSONObject end = oldElement.removeEndTag();
// if (end != null) {
// parent.insertBefore(end, oldElement);
// parent.removeChild(oldElement);
// newNext = end;
// }
// }
}
} else {
newNext = oldElement.getNextSibling();
parent.removeChild(oldElement);
}
// update context
IJSONNode oldParent = this.context.getParentNode();
IJSONNode oldNext = this.context.getNextNode();
if (element == oldParent) {
if (oldNext != null) {
this.context.setCurrentNode(oldNext); // reset for new parent
} else if (newNext != null) {
this.context.setCurrentNode(newNext);
} else {
this.context.setParentNode(parent);
}
} else if (element == oldNext) {
if (firstElement != null) {
this.context.setParentNode(firstElement);
} else if (first != null) {
this.context.setCurrentNode(first);
} else if (startElement != null) {
this.context.setParentNode(startElement);
} else {
this.context.setCurrentNode(newNext);
}
}
// removeImplicitElement(elementParent);
}
private void removeStructuredDocumentRegion(
IStructuredDocumentRegion oldStructuredDocumentRegion) {
JSONNodeImpl node = (JSONNodeImpl) this.context.getCurrentNode();
if (node != null) {
short nodeType = node.getNodeType();
if (nodeType == IJSONNode.OBJECT_NODE
|| nodeType == IJSONNode.ARRAY_NODE
|| nodeType == IJSONNode.PAIR_NODE) {
removeNode(node);
// if(context.getCurrentNode() != null && context.getCurrentNode().equals(node))
// context.setCurrentNode(null);
return;
}
}
}
/**
* replaceRegions method
*
* @param newRegions
* java.util.Vector
* @param oldRegions
* java.util.Vector
*/
void replaceRegions(IStructuredDocumentRegion flatNode,
ITextRegionList newRegions, ITextRegionList oldRegions) {
if (flatNode == null)
return;
if (this.model.getDocument() == null)
return;
this.context = new JSONModelContext(this.model.getDocument());
boolean isWhiteSpaces = false;
if (newRegions != null
&& (oldRegions == null || oldRegions.size() == 0)) {
isWhiteSpaces = true;
Iterator e = newRegions.iterator();
while (e.hasNext() && isWhiteSpaces) {
ITextRegion region = (ITextRegion) e.next();
String regionType = region.getType();
isWhiteSpaces = (regionType == JSONRegionContexts.WHITE_SPACE);
}
if (isWhiteSpaces) {
return;
}
}
// optimize typical cases
String regionType = StructuredDocumentRegionUtil
.getFirstRegionType(flatNode);
if (regionType == JSONRegionContexts.JSON_OBJECT_OPEN) {
changeStartObject(flatNode, newRegions, oldRegions);
}
if(regionType == JSONRegionContexts.JSON_OBJECT_KEY) {
changeAttrName(flatNode, flatNode.getFirstRegion());
} else if (isJSONValue(regionType)) {
changeAttrValue(flatNode, flatNode.getFirstRegion());
} else if(regionType == JSONRegionContexts.JSON_UNKNOWN){
return;
}
// else if (regionType == JSONRegionContexts.JSON_END_TAG_OPEN) {
// changeEndTag(flatNode, newRegions, oldRegions);
// }
else {
changeStructuredDocumentRegion(flatNode);
}
}
/**
* replaceStructuredDocumentRegions method
*
*/
void replaceStructuredDocumentRegions(
IStructuredDocumentRegionList newStructuredDocumentRegions,
IStructuredDocumentRegionList oldStructuredDocumentRegions) {
if (this.model.getDocument() == null)
return;
this.context = new JSONModelContext(this.model.getDocument());
int newCount = (newStructuredDocumentRegions != null ? newStructuredDocumentRegions
.getLength() : 0);
int oldCount = (oldStructuredDocumentRegions != null ? oldStructuredDocumentRegions
.getLength() : 0);
int index;
// Find the first document region from the list that is not a comma
// region
for (index = 0; index < oldCount-1; index++) {
if(!oldStructuredDocumentRegions.item(index).getType().equals(JSONRegionContexts.JSON_COMMA))
break;
}
if(oldCount > 0 && !oldStructuredDocumentRegions.item(index).getType().equals(JSONRegionContexts.JSON_COMMA)) {
// Set up the model context, just ensure the region is not a comma
setupContext(oldStructuredDocumentRegions.item(index));
for (int i = index; i < oldCount; i++) {
IStructuredDocumentRegion documentRegion = oldStructuredDocumentRegions
.item(i);
// Remove the old document region
removeStructuredDocumentRegion(documentRegion);
}
} else {
if (newCount == 0)
return;
// In case the oldStructuredDocumentRegions list is empty find the
// first document region from the list that is not a comma region
for (index = 0; index < newCount-1; index++) {
if(!newStructuredDocumentRegions.item(index).getType().equals(JSONRegionContexts.JSON_COMMA))
break;
}
if(newCount > 0 && !newStructuredDocumentRegions.item(index).getType().equals(JSONRegionContexts.JSON_COMMA)) {
setupContext(newStructuredDocumentRegions.item(index));
}
}
// make sure the parent is set to deepest level
// when end tag has been removed
this.context.setLast();
if (newCount > 0) {
for (int i = 0; i < newCount; i++) {
IStructuredDocumentRegion documentRegion = newStructuredDocumentRegions
.item(i);
// Add each of the new document regions
insertStructuredDocumentRegion(documentRegion);
}
}
this.context.setCurrentNode(null);
}
/**
* setupContext method
*
*/
private void setupContext(
IStructuredDocumentRegion startStructuredDocumentRegion) {
int offset = startStructuredDocumentRegion.getStart();
if (offset < 0)
return;
JSONNodeImpl root = (JSONNodeImpl) this.context.getRootNode();
if (root == null)
return;
if (offset == 0) {
// at the beginning of document
IJSONNode child = root.getFirstChild();
if (child != null)
this.context.setCurrentNode(child);
else
this.context.setParentNode(root);
return;
}
// Get the JSON Node at the specified position in the document, this
// position is the start offset of the flatNode
JSONNodeImpl node = (JSONNodeImpl) root.getNodeAt(offset);
if (node == null) {
// might be at the end of document
this.context.setParentNode(root);
this.context.setLast();
return;
}
if(node.getStartStructuredDocumentRegion() != null) {
if(offset == node.getStartStructuredDocumentRegion().getStartOffset()) {
// This is a JSONPair and the flatNode might be and update of
// the object key value
this.context.setCurrentNode(node);
return;
} else if (node.getEndStructuredDocumentRegion() != null) {
if(offset == node.getEndStructuredDocumentRegion().getStartOffset()) {
// This is a JSONPair and the flatNode might be an update of
// the pair value
this.context.setCurrentNode(node);
return;
}
}
}
if(node instanceof JSONPairImpl && ((JSONPairImpl) node).getValue() != null) {
if(isJSONValue(startStructuredDocumentRegion.getType())) {
// This is a JSONPair and the flatNode might be the pair value
this.context.setCurrentNode(node);
return;
}
}
// In case Node is a JSONObject or JSONArray, look for the current node
// into the children
for (IJSONNode child = node.getFirstChild(); child != null; child = child
.getNextSibling()) {
if (offset >= ((JSONNodeImpl) child).getEndOffset()) {
if(child instanceof JSONPairImpl && ((JSONPairImpl) child).getValue() == null) {
if (isJSONValue(startStructuredDocumentRegion.getType())) {
this.context.setCurrentNode(child);
return;
}
} else {
continue;
}
}
this.context.setCurrentNode(child);
return;
}
// The node is tha paret node of the flatNode
this.context.setParentNode(node);
this.context.setLast();
}
protected JSONModelContext getContext() {
return context;
}
/**
* Returns true if the region type is a JSONValue
*
*/
private boolean isJSONValue(String regionType){
if(regionType == JSONRegionContexts.JSON_VALUE_STRING
|| regionType == JSONRegionContexts.JSON_VALUE_BOOLEAN
|| regionType == JSONRegionContexts.JSON_VALUE_NUMBER
|| regionType == JSONRegionContexts.JSON_VALUE_NULL) {
return true;
}
return false;
}
}