[PYTHON] Zeigen Sie json-Unterschiede auf einfach zu lesende Weise an

Motivation

Ich möchte die Einstellungsparameter des Geräts mit json beibehalten und die Unterschiede vor und nach der Konfigurationsänderung vergleichen. Wenn Sie nur den Unterschied kennen möchten, gibt es verschiedene Bibliotheken wie deepdiff, aber ich möchte es visuell leicht verständlich machen.

Ergebnis

image

Klicken Sie hier für das Original json.

sample_before.json


{
    "hostName": "test01",
    "domainName": "test.local",
    "defaultGateway": "",
    "role": [
        "db",
        "web"
    ],
    "dnsServer": [
        "10.10.10.250",
        "10.10.10.251"
    ],
    "interfaces": [
        {
            "name": "eth1",
            "ipAddress": "10.10.10.1"
        },
        {
            "name": "eth2",
            "ipAddress": "10.10.20.1"
        }
    ],
	"licenses": [
		{
			"name": "eval",
			"application": [
				"db",
				"web"
			]
		}
	]
}

sample_after.json


{
    "hostName": "test02",
    "domainName": "test.local",
    "defaultGateway": "",
    "role": [
        "web",
        "db"
    ],
    "dnsServer": [
        "10.10.10.250",
        "10.10.10.252"
    ],
    "interfaces": [
        {
            "name": "eth1",
            "ipAddress": "10.10.10.1"
        },
        {
            "name": "eth2",
            "ipAddress": "10.10.20.2"
        },
		{
            "name": "eth3",
            "ipAddress": "10.10.30.1"
        }
    ],
	"licenses": [
		{
			"name": "eval",
			"application": [
				"test",
				"web"
			]
		}
	]
}

Annahme

Ich brauche keinen Allzweck, daher gehe ich von folgenden Annahmen aus.

Wie auch immer, ich möchte den Unterschied bemerken, also vergleiche auf der Ebene des Hauptschlüssels, und wenn es vorerst anders ist, drehe die Reihe des Hauptschlüssels gelb, um die Aufmerksamkeit auf sich zu ziehen. Führen Sie anschließend einen detaillierten Vergleich durch und zeigen Sie verschiedene Teile in Rot an.

Realisierungsmethode

Erstellen Sie zunächst HTML mit einer Bibliothek namens json2html. Analysieren Sie dann mit BeautifulSoup4, schreiben Sie die Tags verschiedener Teile neu, kombinieren Sie den HTML-Code und schreiben Sie ihn in eine Datei.

compare.py


from json2html import *
import json
import sys
from bs4 import BeautifulSoup

TAG_WARNING = 'class="tg-warning"'
TAG_DANGER = 'class="tg-danger"'

def check_list(cell_a, cell_b):
    item_cell_a = cell_a.find_all('li')
    item_cell_b = cell_b.find_all('li')
    for j in range(len(item_cell_a)):
        if item_cell_a[j] not in item_cell_b:
            item_cell_a[j].name = 'li ' + TAG_DANGER
    for j in range(len(item_cell_b)):
        if item_cell_b[j] not in item_cell_a:
            item_cell_b[j].name = 'li ' + TAG_DANGER

#Geben Sie eine Fehlermeldung aus, wenn nicht genügend Argumente oder Argumente vorhanden sind.
if len(sys.argv) != 3 or sys.argv[1].split('.')[-1] != 'json' or sys.argv[2].split('.')[-1] != 'json':
    print('''
    Usage: python compare.py <config json> <result json>
    file extension must be 'json'
    This exe generate 'result.html'. Please view this html with any browser.
    ''')
    exit(1)

configfile, resultfile = sys.argv[1], sys.argv[2]
ths = [[], []]
tds = [[], []]
for i, file in enumerate([configfile, resultfile]):
    with open(file, 'r', encoding='utf-8') as f:
        t = json.load(f)
        html = json2html.convert(json=t, table_attributes="class=\"tg\"")
        soup = BeautifulSoup(html, features="html.parser")
        tables = soup.findChildren('table')
        rows = tables[0].find_all('tr', recursive=False)
        ths[i] = [row.find_all('th', recursive=False) for row in rows]
        tds[i] = [row.find_all('td', recursive=False) for row in rows]

th1 = ths[0]
td1, td2 = tds[0], tds[1]

for i in range(len(th1)):
    # First, check top level key's value.
    if td1[i] != td2[i]:
        # If diff, mark header cell as yellow, then drill down
        th1[i][0].name = 'th ' + TAG_WARNING

        if len(td1[i][0].contents) != len(td2[i][0].contents):
            td1[i][0].name = 'td ' + TAG_DANGER
            td2[i][0].name = 'td ' + TAG_DANGER
            continue

        # Case that td content is list or str or dict
        elif len(td1[i][0].contents) == len(td2[i][0].contents) == 1:
            if td1[i][0].contents[0].name == 'table':
                td1_rows = td1[i][0].find_all('tr')
                td2_rows = td2[i][0].find_all('tr')
                if len(td1_rows) == len(td2_rows):
                    for j in range(len(td1_rows)):
                        columns1 = td1_rows[j].find_all('td')
                        columns2 = td2_rows[j].find_all('td')
                        for k in range(len(columns1)):
                            try:
                                if columns1[k].contents[0] != [] and columns2[k].contents[0] != []:
                                    if columns1[k].contents[0].name == 'ul':
                                        check_list(columns1[k], columns2[k])
                                        continue
                                elif columns1[k].contents[0] != [] or columns2[k].contents[0] != []:
                                    columns1[k].name = 'td ' + TAG_DANGER
                                    columns2[k].name = 'td ' + TAG_DANGER
                                    continue
                                if columns1[k] != columns2[k]:
                                    columns1[k].name = 'td ' + TAG_DANGER
                                    columns2[k].name = 'td ' + TAG_DANGER
                            except IndexError as e:
                                if columns1[k] != columns2[k]:
                                    columns1[k].name = 'td ' + TAG_DANGER
                                    columns2[k].name = 'td ' + TAG_DANGER
                else:
                    for j in range(len(td1_rows)):
                        if td1_rows[j] not in td2_rows:
                            td1_rows[j].name = 'tr ' + TAG_DANGER
                    for j in range(len(td2_rows)):
                        if td2_rows[j] not in td1_rows:
                            td2_rows[j].name = 'tr ' + TAG_DANGER
            elif td1[i][0].contents[0].name == 'ul':
                check_list(td1[i][0], td2[i][0])
            else:
                td1[i][0].name = 'td ' + TAG_DANGER
                td2[i][0].name = 'td ' + TAG_DANGER
        else:
            td1[i][0].name = 'td ' + TAG_DANGER
            td2[i][0].name = 'td ' + TAG_DANGER

#Schreiben Sie CSS hinein, um es in einer Datei zu vervollständigen.
html_header = '''
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
.tg  {border-collapse:collapse;border-spacing:0;border-color:skyblue;font-family:Arial, sans-serif;font-size:12px;}
.tg td{padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:skyblue;color:black;vertical-align:top;}
.tg th{font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:skyblue;color:black;background-color:skyblue;vertical-align:top;}
.tg .tg-danger{background-color:orangered  !important;}
.tg .tg-warning{background-color:gold !important;}
ul {
  list-style: none;
}
</style>
</head>
<body>
<table class="tg">
<thead><tr><th>Param</th><th>Before</th><th>After</th></tr></thead>
<tbody>
'''

result = ''
for i in range(len(th1)):
    result += '<tr>' + str(th1[i][0]) + str(td1[i][0]) + str(td2[i][0]) + '</tr>'

html_footer = '''
</tbody>
</table>
</body>
</html>
'''

with open('result.html', 'w', encoding='utf-8') as f:
    f.write(html_header + result + html_footer)

Wie benutzt man

Da ist nichts Besonderes.

git clone https://github.com/KI1208/json_compare.git
pip install -r requirements.txt
python compare.py sample_before.json sample_after.json

Zeigen Sie die generierte result.html im Browser an.

Recommended Posts

Zeigen Sie json-Unterschiede auf einfach zu lesende Weise an
Formatieren Sie eine Zeile json, um die Anzeige zu vereinfachen
Stapelkonvertierung von Excel-Dateien in JSON [Python]
Einfach zu bedienende Flasche
Wie man JSON liest
Einfach zu bedienendes SQLite3
Konvertieren Sie json in Excel
[Python] Ich habe versucht, Json von Tintenfischring 2 zu bekommen
Ein Liner, der JSON formatiert, um die Anzeige zu vereinfachen
Vorgehensweise für die Ajax-Kommunikation von HTML zu JSON auf dem API-Server
So sehen Sie den Inhalt der ipynb-Datei des Jupyter-Notizbuchs
Ich habe versucht, eine Site zu erstellen, mit der die aktualisierten Informationen von Azure einfach angezeigt werden können
[Einführung in cx_Oracle] Übersicht über cx_Oracle
Zuweisung von Ressourcen zum Testen
Einfach zu lesender Kontrollfluss
Analysieren Sie die JSON-Datei zum Objekt
Einfache Möglichkeit, Dateien umzubenennen
Einfach zu bedienendes E-Cell 4 Intermediate
Einfache Implementierung des CSV-Imports in AWS Dynamo DB (Windows, kostenlos)
[Für Anfänger] Rekursive Funktion (Der Turm in Hanoi ist leicht zu verstehen!)