web-dev-qa-db-fra.com

JSON correspondant à un XML avec des attributs?

Je conçois une API pour mon application Web.

Je pensais prendre en charge uniquement les réponses JSON (pas XML), car plus simples.

Mais je viens de tomber sur ce XML:

<folders>
    <folder id="123" private="0" archived="0" order="1">Shopping</folder>
</folders>

et je me demandais comment serait le JSON correspondant. J'ai l'impression que, dans ce cas, XML serait plus compact.

Merci, Dan

28
dan

Peut-être:

{
  "folders": [
    { "id":123, "private":0, "archived":0, "order":1, "title":"Shopping" },
    ...
  ]
}

Comme il existe non une correspondance exacte entre XML et JSON, vous êtes libre (par exemple, vous devez définir) la manière dont les deux structures de données mappent. Par exemple, dans ce qui précède, l'élément "folder" est implicite dans les objets imbriqués dans le tableau "folder".

Cela pourrait être étendu comme dans:

"folders": [{"folder": { .... }]

Etc, mais il y a toujours le problème de ne pas être capable de capturer le contenu + les attributs aussi systématiquement que XML. Dans tous les cas, votre structure de données -> JSON | XML serializer fonctionne probablement d'une manière particulière (et veuillez utiliser une bibliothèque, et non pas "roulée à la main" JSON-munging string ). C'est; le format de XML et JSON doit être dicté de manière uniforme (en quelque sorte) par la structure de données pour la transmission.

18
user166390

Cette approche prend en charge la transformation inverse en XML:

{
    "folders": {
        "folder":{ 
        "@": {
            "id": "123",
            "private": "0",
            "archived": "0",
            "order": "1"
            },
        "#": "Shopping"
        }
    }
}

Cela fonctionne correctement avec js2xmlparser.

14
Supervision

Un exemple de la façon dont YQL présente XML et le JSON correspondant. Inutile de savoir quelque chose à propos de YQL, mais si cela vous intéresse, vous pouvez vérifier la console YQL et l’essayer vous-même dans la console YQL

XML

<results>
    <a href="/">NBA</a>
    <a class="topnav" href="#">TEAMS</a>
    <a href="/teams/">Teams</a>
    <a href="/hawks/">Atlanta</a>

JSON

"results": {
  "a": [
    {
     "href": "/",
     "content": "NBA"
    },
    {
     "class": "topnav",
     "href": "#",
     "content": "TEAMS"
    },
    {
     "href": "/teams/",
     "content": "Teams"
    },
    {
     "href": "/hawks/",
     "content": "Atlanta"
    },
7
spier

Il existe une convention/notation JSON appelée badgerfish qui tente de standardiser (du moins ses propres termes) la manière de conserver la plupart des sémantiques XML de bas niveau lorsque XML DOM est représenté par JSON DOM (avec des attributs bien sûr) (voir http://badgerfish.ning.com/ ).

Ainsi, vous pouvez facilement reconvertir la représentation badgerfishied-json en représentation XML et vous travaillez toujours sur la structure avec votre jeu d'outils XML favori (pour moi, ses expressions et outils XPATH/QUERY).

Il est également facile de mémoriser des règles de syntaxe (total 9) telles que: "Les attributs vont dans les propriétés dont le nom commence par @". Vous pouvez travailler sur badgerfishied-json dans l'éditeur de texte sans surcharger inutilement vos circuits neuronaux. Habituellement, vous pouvez les mémoriser lors du premier passage.

7
underscore

Il me semble que la correspondance la plus exacte entre XML et JSON devrait représenter un nœud XML sous forme de triplet (tableau): [nom, attributs, valeur], nom étant une chaîne, attribue un objet avec des noms d'attributs comme clés. et attribue des valeurs sous forme de (chaîne), et valorise une chaîne (pour les valeurs atomiques) ou un tableau de tels triplets.

Par une telle correspondance, l’équivalent JSON de

<folders>
    <folder id="123" private="0" archived="0" order="1">Shopping</folder>
</folders>

serait

[  "folders",
   {}, 
   [
      [  "folder", 
         {   "id": "123",
             "private": "0",
             "archived": "0",
             "order": "1"
         },
         "Shopping"
      ]
   ]
]

En réalité, l'idée derrière cette cartographie est que:

1) La transformation XML-JSON soit réversible . 2) La relation de "parent" des sous-nœuds soit préservée

Dans le même temps, la distinction entre les nœuds d’attribut et les nœuds de valeur est explicite ici.

Est-ce que ça fait du sens? Et justifie-t-il la surcharge de temps?

4
Aram Gharib

Pourrait aussi être compact dans le JSON, l'attribut est identique à la valeur dans la balise

d'ici: 

http://www.json.org/example.html

{"widget": {
    "debug": "on",
    "window": {
        "title": "Sample Konfabulator Widget",
        "name": "main_window",
        "width": 500,
        "height": 500
    },
    "image": { 
        "src": "Images/Sun.png",
        "name": "Sun1",
        "hOffset": 250,
        "vOffset": 250,
        "alignment": "center"
    }
}}  

Le même texte exprimé en XML:

<widget>
    <debug>on</debug>
    <window title="Sample Konfabulator Widget">
        <name>main_window</name>
        <width>500</width>
        <height>500</height>
    </window>
    <image src="Images/Sun.png" name="Sun1">
        <hOffset>250</hOffset>
        <vOffset>250</vOffset>
        <alignment>center</alignment>
    </image>
</widget>
3
Roman Goyenko

modifier

Une méthode similaire est préconisée sur http://www.jsonml.org/ . Ils ont inventé le terme json markup language.


Vous pouvez choisir n’importe quel mappage, mais si vous mappez

<el attr="value">
  txt
</el>

à

{"el":{"attr":"value","content":"txt"}}

alors comment voulez-vous cartographier:

<el attr="value" content="txt1">txt2</el>

J'utiliserais le fait que certains noms d'attributs sont interdits.

{"el":{"attr":"value", "content":"txt1", "":["txt"]}

Ou un exemple plus complexe:

<widget>
  <debug>on</debug>
  <window title="Sample Konfabulator Widget">
    I just put some text here
    <name>main_window</name>
    <width>500</width>
    <height>500</height>
  </window>
  <image src="Images/Sun.png" name="Sun1">
    <hOffset>250<unit>mm</unit></hOffset>
    <vOffset>250</vOffset>
    <alignment>center</alignment>
  </image>
</widget>

pourrait mapper à:

{"widget":{"":[
  {"debug":{"":["on"]}},
  {"window":{"title":"Sample Konfabulator Widget", "": [
    "I just put some text here",
    {"name":{"":["main window"]}},
    {"width":{"":["500"]}},
    {"height":{"":["500"]}}
  ]},
  {"image":{"src":"Images/Sun.png", "name":"Sun1", "":[
    {"hOffset":{"":["250",{"unit":{"":["mm"]}}]}},
    {"vOffset":{"":["250"]}},
    {"alignment":{"":["center"]}}
  }
]}

Les règles pour cette conversion sont sans ambiguïté:

  • un élément est converti en objet.
  • La clé d'objet est le nom de l'élément.
  • La valeur de l'objet est un objet lui-même, avec:
    • un attribut est mappé sur une propriété d'objet. (valeur clé)
    • le contenu de l'objet est associé à une propriété spéciale .
      • Le nom de la propriété spéciale est une chaîne vide. Cela ne peut jamais entrer en collision avec un nom d'attribut xml.
      • La valeur de la propriété spéciale est un tableau.
      • Dans le tableau, le texte brut est représenté par une chaîne.
      • Dans le tableau, les éléments sont représentés sous forme d'objets, comme décrit ci-dessus.

Pour sécuriser l'espace, il existe un moyen de simplifier sans ambiguïté le mappage mentionné:

{"widget":{"":[
  {"debug":"on"},
  {"window":{"title":"Sample Konfabulator Widget", "": [
    "I just put some text here",
    {"name":"main window"},
    {"width":"500"},
    {"height":"500"}
  ]},
  {"image":{"src":"Images/Sun.png", "name":"Sun1", "":[
    {"hOffset":["250",{"unit":"mm"}]},
    {"vOffset":"250"},
    {"alignment":"center"}
  }
]}
  • Si un élément n'a pas d'attribut, l'objet value (contenant le mappage spécial de chaîne vide sur un tableau) est remplacé directement par le tableau. Donc au lieu de:

    {"hOffset": {"": ["250", {"unité": {"": ["mm"]}}}}}

vous recevez

{"hOffset":["250",{"unit":["mm"]}]}
  • Si le contenu de l'élément est uniquement du texte, le tableau contenant la valeur de chaîne est remplacé directement par la valeur de chaîne. Vous obtenez donc:

    {"hOffset": ["250", {"unité": "mm"}]}

De cette façon, il y aura toujours exactement un moyen de mapper le jml (json markup language) vers xml (ou html)

1
realbart

"contenu" est utilisé pour le texte réel, tandis que les attributs sont ses frères et soeurs dans le JSON résultant:

{ "folders":
 { "folder":
  {
   "archived":0,
   "private":0,
   "id":123,
   "content":"Shopping",
   "order":1
  }
 }
}

Détails d'implémentation Java

0
Menashe Eliezer

Si vous souhaitez avoir un aperçu des différentes conventions pour la conversion XML en JSON, vous trouverez un aperçu de Nice à l’adresse: http://wiki.open311.org/JSON_and_XML_Conversion/

Une bibliothèque python prenant en charge plusieurs conventions est xmljson ( https://github.com/sanand0/xmljson ).

0
Dag Wieers

J'ai rencontré un scénario nécessitant à la fois XML et JSON pour les entrées et les sorties en fonction de ce qui était transmis. J'ai trouvé un moyen qui fonctionne avec les attributs/propriétés XML et JSON. Notez maintenant que c'est la façon dont cela a été codé en Java, qui le fait fonctionner de cette façon.

Mon exemple XML:

<Log>
    <datetime>05/05/2017 13:45:22</datetime>
    <sessionid>2da236d2-3852-4a09-8067-198193d2828b</sessionid>
    <message msgType="Debug">This is my message</message>
</Log>

Mon exemple JSON:

{
    "datetime":"05/05/2017 13:45:22",
    "sessionid":"2da236d2-3852-4a09-8067-198193d2828b",
    "message": {
        "content":"This is a testa",
        "msgType":"Debug"
    }
}

Comment je l'ai fait fonctionner via code Log.Java :

package log;

import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;

@JacksonXmlRootElement(localName = "Log")
public class Log {
    @JacksonXmlProperty(localName = "datetime")
    private String datetime;
    @JacksonXmlProperty(localName = "sessionid")
    private String sessionid;
    @JacksonXmlProperty(localName = "message")
    private Message message;

    public Log() {
        this.sessionid = "0";
        this.datetime = "";
        this.message = new Message();
    }

    public String getDatetime() {
        return datetime;
    }

    public void setDatetime(String datetime) {
        this.datetime = datetime;
    }

    public String getSessionid() {
        return sessionid;
    }

    public void setSessionid(String sessionid) {
        this.sessionid = sessionid;
    }

    public Message getMessage() {
        return message;
    }

    public void setMessage(Message message) {
        this.message = message;
    }
}

Message.Java , Notez le @JacksonXmlText ci-dessous, qui est la clé:

package log;

import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText;

public class Message {
    @JacksonXmlProperty(localName = "msgType", isAttribute = true)
    private String msgType;
    @JacksonXmlText
    private String content;

    public Message() {
        this.content = "";
    }

    public String getMsgType() {
        return msgType;
    }

    public void setMsgType(String msgType) {
        switch(msgType.toLowerCase())
        {
        case "test":
        case "debug":
        case "warn":
        case "error":
            break;
        default:
            msgType = "Unknown";
            break;
        }

        this.msgType = msgType;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}

Appelant dans LogController.Java :

..
@RequestMapping(value = "/Logger", produces={"application/xml", "application/json"}, consumes={"application/xml", "application/json"})
public ResponseEntity<String> Logger(@RequestBody String logInfo, @RequestHeader("Content-Type") String contentType) {
    try 
    {
        String xml = "";
        Log logObj = null; 
        HttpHeaders responseHeaders = new HttpHeaders();
        responseHeaders.add("Content-Type", contentType);

        if (contentType.toLowerCase().contains("json"))
        {
           ObjectMapper mapper = new ObjectMapper();
           logObj = mapper.readValue(logInfo, Log.class);
           xml = mapper.writeValueAsString(logObj);
        }
        else if (contentType.toLowerCase().contains("xml"))
        {
           XmlMapper xmlMapper = new XmlMapper();
           logObj = xmlMapper.readValue(logInfo, Log.class);
           xml = xmlMapper.writeValueAsString(logObj);
        }
        else
           return new ResponseEntity<String>(HttpStatus.BAD_REQUEST);

        //TODO GWL
        //Save Log data, via Async Web Service, Data, or System 
        return new ResponseEntity<String>(xml, responseHeaders, HttpStatus.OK);
    } 
    catch( Exception ex)
    {
        ex.printStackTrace();
        return new ResponseEntity<String>(HttpStatus.BAD_REQUEST);
    }
}
0
Switch

JSON est plus uniforme que XML et ne fait pas de distinction entre les attributs de texte brut et le contenu hiérarchique. La représentation naturelle de votre exemple serait

[
  {"id": 123, "private": 0, "archived": 0, "order": 1, "name": "Shopping"}
]

C'est encore plus compact que le XML respectif.

0
Adam Byrtek

Mise en garde: Dans cette réponse, je m'éloigne délibérément de la question initiale et élargis quelque peu la portée. Parfois, pour poser la question derrière la question, nous devons d'abord regarder la grande image.

Tout comme tous les animaux sont égaux, toutes les traductions de JSON en XML et de XML en JSON sont inégales. Il ne peut y avoir de réponses mathématiquement correctes à cette question, et même si elles existent, elles peuvent être fausses. Toutes les réponses seront une question d'opinion et dépendront du ou des cas d'utilisation exacts.

JSON et XML prennent en charge et omettent les concepts rendant difficiles les traductions parfaites, réversibles et natives.

Pour n'en nommer que quelques uns:

  • XML nécessite un élément racine. JSON ne le fait pas.

  • XML distingue les éléments et les attributs. Les attributs sont des feuilles, des éléments peuvent être des feuilles ou des branches. Les objets JSON sont proches des éléments, mais n'ont pas d'équivalent direct aux attributs.

  • JSON a des tableaux; L'équivalent XML le plus proche est un élément parent, mais certaines traductions sont erronées lorsqu'il n'y a qu'un seul élément enfant.

  • XML a des espaces de noms… .. Moins on en dit, mieux c'est…

  • JSON est destiné à être compact et léger, et est plus proche (à mon humble avis) de YAML que de XML.

Lorsqu'un concept existe dans la langue source, mais pas dans la langue cible, nous devons faire preuve d'inventivité et de créativité dans notre traduction. Vos cas d'utilisation sont la clé.

par exemple.

  • Le résultat doit-il être aussi natif que possible dans la langue cible? Le modéliserions-nous comme ceci en JSON? Le modéliserions-nous comme ceci en XML?

  • Le résultat devrait-il être réversible par rapport à la source d'origine, même au détriment du «sentiment autochtone»?

  • La compacité est-elle un critère? Cela peut être le cas pour JSON sur un XML lourd en éléments, mais pas pour JSON traduit à partir de XML et conçu pour être traduit en arrière.

Pour faire une comparaison avec les langues humaines: En Suisse allemand, nous aimons nos diminutifs: les noms sont systématiquement réduits à la forme la plus petite où ce serait étrange en anglais; mais encore plus bizarre, nous avons des diminutifs de verbes!

Donc: “wir machen es köchele”, pourrait traduire techniquement “nous allons cuisiner un peu”, ou “nous faisons un peu de cuisine” mais soit un anglais médiocre et incorrect, et passer à côté de l'idée.

«Nous ferons un peu de cuisine» ou «nous nous amuserons de cuisiner» serait beaucoup plus proche de l'idée originale. Mais je soupçonne qu’Anthea Bell (de la renommée de la traduction d’Astérix en anglais) aurait vraiment compris; Faisons cuire un festin…

Retour à la question initiale. Les programmeurs Python ont un concept de pythonesque: = plus adapté à la philosophie de base de python. La réponse de user166390 (la réponse acceptée au moment de cette réponse) me semble être la réponse la plus JSON.

0
FlyingSheep