JSON 파일 정규화
자동으로 생성된 JSON 파일을 버전 관리에 저장하고 싶습니다.문제는 파일이 시리얼화될 때마다 속성이 다른 순서로 표시되기 때문에 파일이 실제로 변경되었는지, 실제 차이가 무엇인지 알 수 없다는 것입니다.
이 작업을 수행할 기존 오픈 소스 도구를 알고 있는 사람이 있습니까?
그렇지 않으면 파서와 제너레이터를 갖춘 JSON 라이브러리를 아는 사람이 있습니까? (예를 들어) 알파벳 순서로 속성을 가진 "예쁜" JSON을 출력하도록 구성할 수 있습니다. (Java 또는 Ruby 라이브러리가 이상적이지만 다른 리드도 환영입니다.)
Python의 JSON 모듈은 다른 프로그램에서도 매우 사용할 수 있습니다.
generate_json | python -mjson.tool > canonical.json
전화하셔서 약간의 오버헤드를 겪고 싶으시면
gson.toJson(canonicalize(gson.toJsonTree(obj)));
그런 다음 다음과 같은 작업을 수행할 수 있습니다.
protected static JsonElement canonicalize(JsonElement src) {
if (src instanceof JsonArray) {
// Canonicalize each element of the array
JsonArray srcArray = (JsonArray)src;
JsonArray result = new JsonArray();
for (int i = 0; i < srcArray.size(); i++) {
result.add(canonicalize(srcArray.get(i)));
}
return result;
} else if (src instanceof JsonObject) {
// Sort the attributes by name, and the canonicalize each element of the object
JsonObject srcObject = (JsonObject)src;
JsonObject result = new JsonObject();
TreeSet<String> attributes = new TreeSet<>();
for (Map.Entry<String, JsonElement> entry : srcObject.entrySet()) {
attributes.add(entry.getKey());
}
for (String attribute : attributes) {
result.add(attribute, canonicalize(srcObject.get(attribute)));
}
return result;
} else {
return src;
}
}
이는 잭슨에서 지원됩니다.
@JsonPropertyOrder(알파벳=true)
오픈 소스 Java 라이브러리 Jackson은 셋업하는 데 다소 시간이 걸릴 수 있지만 예쁜 인쇄가 가능하고 꽤 깔끔합니다.@JsonPropertyOrder알파벳 또는 수동으로 지정된 출력 순서를 지원하는 주석입니다.
많은 조합을 시도하지는 않았지만, 구글-gson이 속성의 순서를 유지하고 있는 것 같습니다.JSON.
더 이상 관련이 없기 때문에 여기서 예를 삭제했습니다.
이전 프로젝트의 경험에서 알 수 있듯이 기본 객체가 충분하지 않은 경우 Gson Builder를 사용하여 보다 복잡한 어댑터를 만들 수 있습니다.
다만, 사용 사례에서 광범위하게 테스트한 것은 아닙니다만, 예상한 출력이 있는지 확인하는 것은 간단할 것입니다.
갱신하다
SVN/CVS를 사용하여 파일이 변경되었는지 여부를 확인하는 대신 GSON에는 사용자의 문제를 해결할 수 있는 내장 버전 관리 지원이 포함되어 있습니다.
@Since 주석을 사용하여 동일한 개체의 여러 버전을 유지할 수 있습니다.이 주석은 클래스, 필드 및 향후 릴리스에서는 메서드에서 사용할 수 있습니다.이 기능을 이용하려면 버전 번호보다 큰 필드/오브젝트를 무시하도록 Gson 인스턴스를 설정해야 합니다.Gson 인스턴스에 버전이 설정되어 있지 않은 경우 버전에 관계없이 모든 필드 및 클래스가 시리얼화 및 역직렬화됩니다.
갱신하다
내가 생각할 수 있는 유일한 것은 외부 파일을 코뿔소로 해석하고 해석된 파일을 변환하는 것입니다.
JSON문자열로 돌아가면 단일 '파서'를 통해 실행되며 출력은 다르지 않습니다.
그런 다음 가능한 변경을 감지할 수 있습니다.
Ruby 1.9+는 해시 삽입 순서를 유지하며, JSON for 1.9+는 이를 준수합니다.
asdf = {'a' => 1, 'b' => 2}
asdf.to_json # => "{\"a\":1,\"b\":2}"
asdf = {'b' => 1, 'a' => 2}
asdf.to_json # => "{\"b\":1,\"a\":2}"
"예쁜" 형식을 생성하는 방법은 다음과 같습니다.
asdf = {'a' => 1, 'b' => 2}
puts JSON.pretty_generate(asdf)
{
"a": 1,
"b": 2
}
asdf = {'b' => 1, 'a' => 2}
irb(main):022:0> puts JSON.pretty_generate(asdf)
{
"b": 1,
"a": 2
}
...같은 속성이 다른 순서로 삽입되고 있습니다...
이해가 잘 안 가지만, 한 번 해볼게.
Ruby는 삽입 순서를 유지하기 때문에 해시를 정해진 순서로 작성해도 데이터 순서가 중요하지 않습니다.키를 정렬하고 해시를 재생성하여 순서를 강제하여 JSON에 전달합니다.
require 'json'
puts Hash[{'a' => 1, 'b' => 2}.sort_by{ |a| a }].to_json
=> {"a":1,"b":2}
puts Hash[{'b' => 2, 'a' => 1}.sort_by{ |a| a }].to_json
=> {"a":1,"b":2}
puts Hash[{'b' => 2, 'c' => 3, 'a' => 1}.sort_by{ |a| a }].to_json
=> {"a":1,"b":2,"c":3}
puts Hash[{'b' => 2, 'c' => 3, 'a' => 1}.sort_by{ |a| a }].to_json
=> {"a":1,"b":2,"c":3}
puts Hash[{'a' => 1, 'c' => 3, 'b' => 2}.sort_by{ |a| a }].to_json
=> {"a":1,"b":2,"c":3}
여기 Qt의 간단한 JSON 인코더가 있습니다. Java로 재캐스팅하는 것은 비교적 쉬울 것입니다.실제로 필요한 것은 쓰기 시 키가 정렬되었는지 확인하는 것입니다.는 다른 JSON 패키지를 사용하여 읽을 수 있습니다.
QString QvJson::encodeJson(const QVariant& jsonObject) {
QVariant::Type type = jsonObject.type();
switch (type) {
case QVariant::Map:
return encodeObject(jsonObject);
case QVariant::List:
return encodeArray(jsonObject);
case QVariant::String:
return encodeString(jsonObject);
case QVariant::Int:
case QVariant::Double:
return encodeNumeric(jsonObject);
case QVariant::Bool:
return encodeBool(jsonObject);
case QVariant::Invalid:
return encodeNull(jsonObject);
default:
return encodingError("encodeJson", jsonObject, ErrorUnrecognizedObject);
}
}
QString QvJson::encodeObject(const QVariant& jsonObject) {
QString result("{ ");
QMap<QString, QVariant> map = jsonObject.toMap();
QMapIterator<QString, QVariant> i(map);
while (i.hasNext()) {
i.next();
result.append(encodeString(i.key()));
result.append(" : ");
result.append(encodeJson(i.value()));
if (i.hasNext()) {
result.append(", ");
}
}
result.append(" }");
return result;
}
QString QvJson::encodeArray(const QVariant& jsonObject) {
QString result("[ ");
QList<QVariant> list = jsonObject.toList();
for (int i = 0; i < list.count(); i++) {
result.append(encodeJson(list.at(i)));
if (i+1 < list.count()) {
result.append(", ");
}
}
result.append(" ]");
return result;
}
QString QvJson::encodeString(const QVariant &jsonObject) {
return encodeString(jsonObject.toString());
}
QString QvJson::encodeString(const QString& value) {
QString result = "\"";
for (int i = 0; i < value.count(); i++) {
ushort chr = value.at(i).unicode();
if (chr < 32) {
switch (chr) {
case '\b':
result.append("\\b");
break;
case '\f':
result.append("\\f");
break;
case '\n':
result.append("\\n");
break;
case '\r':
result.append("\\r");
break;
case '\t':
result.append("\\t");
break;
default:
result.append("\\u");
result.append(QString::number(chr, 16).rightJustified(4, '0'));
} // End switch
}
else if (chr > 255) {
result.append("\\u");
result.append(QString::number(chr, 16).rightJustified(4, '0'));
}
else {
result.append(value.at(i));
}
}
result.append('"');
QString displayResult = result; // For debug, since "result" often doesn't show
Q_UNUSED(displayResult);
return result;
}
QString QvJson::encodeNumeric(const QVariant& jsonObject) {
return jsonObject.toString();
}
QString QvJson::encodeBool(const QVariant& jsonObject) {
return jsonObject.toString();
}
QString QvJson::encodeNull(const QVariant& jsonObject) {
return "null";
}
QString QvJson::encodingError(const QString& method, const QVariant& jsonObject, Error error) {
QString text;
switch (error) {
case ErrorUnrecognizedObject:
text = QObject::tr("Unrecognized object type");
break;
default:
Q_ASSERT(false);
}
return QObject::tr("*** Error %1 in QvJson::%2 -- %3").arg(error).arg(method).arg(text);
}
시리얼화할 개체의 키를 출력하기 전에 정렬합니다.Ruby 1.9에서는 기본적으로 해시가 주문되지만, Ruby 1.8에서는 그렇지 않습니다.active_support에서 OrderedHash를 사용하여 두 경우 모두 확인할 수 있습니다.
JSON j j j j j j j j j j j j j j j j j j j.수 1.8로 전화해야 합니다.to_s당신 타입으로.
require 'rubygems'
require 'json'
require 'active_support/ordered_hash'
obj = {
:fig => false,
:bananas => false,
:apples => true,
:eggplant => true,
:cantaloupe => true,
:dragonfruit => false
}
def sorted_hash(hsh)
sorted_keys = hsh.keys.sort_by { |k| k.to_s }
sorted_keys.inject(ActiveSupport::OrderedHash.new) do |o_hsh, k|
o_hsh[k] = hsh[k]
o_hsh
end
end
puts JSON.pretty_generate(obj)
# Could output in any order, depending on version of Ruby
# {
# "eggplant": true,
# "cantaloupe": true,
# "dragonfruit": false,
# "fig": false,
# "bananas": false,
# "apples": true
# }
puts JSON.pretty_generate(sorted_hash(obj))
# Always output in the same order
# {
# "apples": true,
# "bananas": false,
# "cantaloupe": true,
# "dragonfruit": false,
# "eggplant": true,
# "fig": false
# }
데이터가 객체 배열 또는 중첩된 객체로 구성된 경우 정렬된 해시를 반복적으로 작성해야 합니다.
nested_obj = {:a => {:d => true, :b => false}, :e => {:k => false, :f => true}, :c => {:z => false, :o => true}}
def recursive_sorted_hash(hsh)
sorted_keys = hsh.keys.sort_by { |k| k.to_s }
sorted_keys.inject(ActiveSupport::OrderedHash.new) do |o_hsh, k|
o_hsh[k] = hsh[k].is_a?(Hash) ? recursive_sorted_hash(hsh[k]) : hsh[k]
o_hsh
end
end
puts JSON.pretty_generate(nested_obj)
# Again, could be in any order
# {
# "a": {
# "b": false,
# "d": true
# },
# "e": {
# "f": true,
# "k": false
# },
# "c": {
# "z": false,
# "o": true
# }
# }
puts JSON.pretty_generate(recursive_sorted_hash(nested_obj))
# Even nested hashes are in alphabetical order
# {
# "a": {
# "b": false,
# "d": true
# },
# "c": {
# "o": true,
# "z": false
# },
# "e": {
# "f": true,
# "k": false
# }
# }
언급URL : https://stackoverflow.com/questions/12584744/canonicalizing-json-files
'programing' 카테고리의 다른 글
| HQL 쿼리에서 휴지 상태 테이블이 매핑되지 않음 오류 (0) | 2023.03.05 |
|---|---|
| VS 코드가 모든 워드프레스 함수 이름을 강조 표시함 (0) | 2023.03.05 |
| AngularJS에서 CSS 스타일을 조건부로 적용하는 방법은 무엇입니까? (0) | 2023.03.05 |
| 각도 2:컴포넌트를 렌더링하기 전에 데이터를 로드하는 방법 (0) | 2023.03.05 |
| JSON과 BSON의 비교 (0) | 2023.03.05 |