Ich habe in Go eine API erstellt, die beim Aufruf eine Abfrage ausführt, eine Instanz einer Struktur erstellt und diese Struktur dann als JSON codiert, bevor sie an den Aufrufer zurückgesendet wird. Ich möchte dem Aufrufer jetzt ermöglichen, die spezifischen Felder auszuwählen, die er zurückgeben möchte, indem er einen GET-Parameter "Felder" übergibt.
Dies bedeutet, dass sich meine Struktur abhängig von den Feldwerten ändern würde. Gibt es eine Möglichkeit, Felder aus einer Struktur zu entfernen? Oder sie zumindest dynamisch in der JSON-Antwort ausblenden? (Hinweis: Manchmal habe ich leere Werte, sodass das JSON-Tag omitEmpty hier nicht funktioniert.) Wenn beides nicht möglich ist, gibt es einen Vorschlag für eine bessere Vorgehensweise? Danke im Voraus.
Eine kleinere Version der von mir verwendeten Strukturen ist unten aufgeführt:
type SearchResult struct {
Date string `json:"date"`
IdCompany int `json:"idCompany"`
Company string `json:"company"`
IdIndustry interface{} `json:"idIndustry"`
Industry string `json:"industry"`
IdContinent interface{} `json:"idContinent"`
Continent string `json:"continent"`
IdCountry interface{} `json:"idCountry"`
Country string `json:"country"`
IdState interface{} `json:"idState"`
State string `json:"state"`
IdCity interface{} `json:"idCity"`
City string `json:"city"`
} //SearchResult
type SearchResults struct {
NumberResults int `json:"numberResults"`
Results []SearchResult `json:"results"`
} //type SearchResults
Ich codiere dann die Antwort und gebe sie wie folgt aus:
err := json.NewEncoder(c.ResponseWriter).Encode(&msg)
Antworten:
EDIT: Ich habe ein paar Abstimmungen bemerkt und mir diese Fragen und Antworten noch einmal angesehen. Die meisten Leute scheinen zu vermissen, dass das OP die dynamische Auswahl von Feldern basierend auf der vom Anrufer bereitgestellten Liste von Feldern verlangte . Sie können dies nicht mit dem statisch definierten json struct-Tag tun.
Wenn Sie immer ein Feld zur JSON-Codierung überspringen möchten
json:"-"
, ignorieren Sie das Feld natürlich (beachten Sie auch, dass dies nicht erforderlich ist, wenn Ihr Feld nicht exportiert wird - diese Felder werden vom JSON-Encoder immer ignoriert). Das ist aber nicht die Frage des OP.Um den Kommentar zur
json:"-"
Antwort zu zitieren :In diesem Fall würde ich anstelle einer Struktur eine map [string] -Schnittstelle {} verwenden. Sie können Felder einfach entfernen, indem Sie das
delete
in der Karte integrierte Element aufrufen, damit die Felder entfernt werden.Das heißt, wenn Sie nicht erst die angeforderten Felder abfragen können.
quelle
map[string]interface{}
zwar sinnvoll, erfordert jedoch nicht, dass Sie Ihre Typdefinition wegwerfen.Id
, aber nicht die gesamte json-Struktur zurückgeben möchte. Danke dafür!benutze `json:" - "`
doc: http://golang.org/pkg/encoding/json/#Marshal
quelle
Ein anderer Weg , dies zu tun , ist es, eine Struktur zu haben , Zeiger mit dem
,omitempty
Tag. Wenn die Zeiger Null sind , werden die Felder nicht gemarshallt.Diese Methode erfordert keine zusätzliche Reflexion oder ineffiziente Verwendung von Karten.
Gleiches Beispiel wie Jorelli mit dieser Methode: http://play.golang.org/p/JJNa0m2_nw
quelle
Sie können das
reflect
Paket verwenden, um die gewünschten Felder auszuwählen, indem Sie über die Feld-Tags nachdenken und diejson
Tag-Werte auswählen . Definieren Sie eine Methode auf dem Search Typ, der wählt die gewünschten Felder und gibt sie als einmap[string]interface{}
, und dann Marschall , dass anstelle der Search selbst struct. Hier ist ein Beispiel, wie Sie diese Methode definieren können:und hier ist eine ausführbare Lösung, die zeigt, wie Sie diese Methode aufrufen und Ihre Auswahl zusammenstellen würden: http://play.golang.org/p/1K9xjQRnO8
quelle
Ich habe gerade Sheriff veröffentlicht , der Strukturen in eine Karte umwandelt, die auf Tags basiert, die in den Strukturfeldern mit Anmerkungen versehen sind. Sie können dann die generierte Karte marshallen (JSON oder andere). Es erlaubt Ihnen wahrscheinlich nicht, nur die vom Anrufer angeforderten Felder zu serialisieren, aber ich kann mir vorstellen, dass die Verwendung einer Gruppe von Gruppen es Ihnen ermöglichen würde, die meisten Fälle abzudecken. Die direkte Verwendung von Gruppen anstelle der Felder würde höchstwahrscheinlich auch die Cache-Fähigkeit erhöhen.
Beispiel:
quelle
Nehmen Sie drei Zutaten:
Das
reflect
Paket, das alle Felder einer Struktur durchläuft.Eine
if
Anweisung zum Aufnehmen der gewünschten FelderMarshal
undDas
encoding/json
Paket nachMarshal
Ihren Wünschen.Vorbereitung:
Mischen Sie sie in einem guten Verhältnis. Verwenden Sie
reflect.TypeOf(your_struct).Field(i).Name()
diese Option , um einen Namen für dasi
dritte Feld von zu erhaltenyour_struct
.Verwenden Sie
reflect.ValueOf(your_struct).Field(i)
diese Option , um eine TypdarstellungValue
einesi
th-Felds von zu erhaltenyour_struct
.Verwenden Sie
fieldValue.Interface()
diese Option, um den tatsächlichen Wert (der auf den Typ interface {} übertragen wurde)fieldValue
des Typs abzurufenValue
(beachten Sie die Verwendung der Klammer - die Interface () -Methode erzeugtinterface{}
Wenn Sie es glücklicherweise schaffen, dabei keine Transistoren oder Leistungsschalter zu verbrennen, sollten Sie Folgendes erhalten:
Portion:
dienen mit einer beliebigen Struktur und einer Reihe
map[string]bool
von Feldern, die Sie beispielsweise einschließen möchtenGuten Appetit!
quelle
Sie können das Tagging-Attribut "omitifempty" verwenden oder optionale Feldzeiger erstellen und die zu überspringenden Felder nicht initialisiert lassen.
quelle
Ich war auch mit diesem Problem konfrontiert. Zuerst wollte ich nur die Antworten in meinem http-Handler spezialisieren. Mein erster Ansatz bestand darin, ein Paket zu erstellen, das die Informationen einer Struktur in eine andere Struktur kopiert und diese zweite Struktur dann zusammenstellt. Ich habe dieses Paket mit Reflection gemacht, also hat mir dieser Ansatz nie gefallen und ich war auch nicht dynamisch.
Deshalb habe ich beschlossen, das encoding / json-Paket zu ändern, um dies zu tun. Die Funktionen
Marshal
,MarshalIndent
und(Encoder) Encode
empfängt zusätzlich eintype F map[string]F
Ich wollte einen JSON der Felder simulieren, die zum Marshalling benötigt werden, daher werden nur die Felder in der Karte gemarshallt.
https://github.com/JuanTorr/jsont
quelle
Die Frage ist jetzt etwas alt, aber ich bin vor einiger Zeit auf dasselbe Problem gestoßen, und da ich keinen einfachen Weg gefunden habe, dies zu tun, habe ich eine Bibliothek gebaut, die diesen Zweck erfüllt. Es ermöglicht die einfache Generierung einer
map[string]interface{}
aus einer statischen Struktur.https://github.com/tuvistavie/structomap
quelle
[]byte
ist, dass es nicht sehr wiederverwendbar ist: Es ist beispielsweise keine einfache Möglichkeit, anschließend ein Feld hinzuzufügen. Daher würde ich vorschlagen, einen zu erstellenmap[string]interface{}
und den JSON-Serialisierungsteil in die Standardbibliothek zu übernehmen.Ich hatte nicht das gleiche Problem, aber ähnlich. Der folgende Code löst natürlich auch Ihr Problem, wenn Sie nichts gegen Leistungsprobleme haben. Bevor Sie diese Art von Lösung in Ihr System implementieren, empfehle ich Ihnen, Ihre Struktur neu zu gestalten, wenn Sie können. Das Senden einer Antwort mit variabler Struktur ist überentwickelt. Ich glaube, eine Antwortstruktur stellt einen Vertrag zwischen einer Anfrage und einer Ressource dar und sollte keine abhängigen Anfragen sein (Sie können unerwünschte Felder auf Null setzen, das tue ich). In einigen Fällen müssen wir dieses Design implementieren. Wenn Sie glauben, dass Sie sich in diesen Fällen befinden, finden Sie hier den von mir verwendeten Play-Link und Code.
quelle
Ich habe diese Funktion erstellt, um Struktur in JSON-Zeichenfolge zu konvertieren, indem einige Felder ignoriert wurden. Hoffe es wird helfen.
Beispiel: https://play.golang.org/p/nmq7MFF47Gp
quelle