Quali approcci possono essere utilizzati per convertire la struttura JSON esistente in una struttura XML esistente?

0

Sto lavorando su un componente per una coda di messaggi aziendali che consuma un messaggio da una coda e lo invia come messaggio di testo. Il messaggio viene raccolto dal mio utente in formato JSON (non ho la possibilità di modificare la modalità di ricezione del messaggio).

{
   "id":"19ADFASDFGG456SDGE",
   "body":"Hello World!",
   "to":[15189511011, 19178567788]
}

Una volta ricevuto dal mio utente ho bisogno di compilare un file XML come questo

<Request>
   <Identification>
      <UserID>CONSTANT_USER</UserID>
      <Password>CONSTANT_PASS</Password>
   </Identification>
   <Service>
      <ServiceName>SendMessage</ServiceName>
      <ServiceDetail>
         <CombiMessage>
            <CombiList>
               <Individual type='sms'>${to}</Individual>
            </CombiList>
            <Text>${body}</Text>
         </CombiMessage>
      </ServiceDetail>
   </Service>
</Request>

Dove ${to} e ${body} vengono popolati dall'oggetto JSON. Questo XML non può essere generato nel codice (deve risiedere in una cartella di risorse come un file xml). Oltre a consumare il messaggio e successivamente a inviare un messaggio di testo, l'utente dispone anche delle funzionalità di registrazione e passa l'oggetto JSON (o un POJO contenente tali dati) a un altro sistema.

Fondamentalmente quando un oggetto JSON viene consumato dalla coda in questo momento sto usando una libreria chiamata Jackson per popolare un Pojo che assomiglia a questo.

public class Message {
    private Set<PhoneNumber> to;
    private String body;
    private String id;
}

E l'oggetto JSON popola quel Pojo tramite Jackson in questo modo.

public static Message getMessage(String json) {
    ObjectMapper mapper = new ObjectMapper();

    return mapper.readValue(json, Message.class);
}

Da lì ora ho un POJO che è una copia esatta dell'oggetto JSON e posso inviarlo al sistema di registrazione, all'altro sistema, e posso anche inserire l'XML con esso.

Tuttavia non ho trovato un modo ideale per popolare l'XML. Attualmente ho qualcosa di semplice come questo

private static String populate(String request, Message message) {
    return request.replaceAll("${to}", message.getTo().toString()).replaceAll("${body}", message.getBody());
}

Questo va bene a questo proposito, ma solo perché ho semplificato eccessivamente per fare questa domanda. A volte il file XML ha quasi mille campi che devono essere popolati. Qualcuno può raccomandare una soluzione per questo ultimo passo? Come farlo dinamicamente? Fondamentalmente vorrei mappare i campi nel mio POJO con i nodi nel file xml (ricordando anche che ho bisogno di mantenere il file xml esterno).

    
posta Chris Maggiulli 27.07.2017 - 15:43
fonte

3 risposte

1

Vorrei utilizzare il DOM o un motore di template come FreeMarker per generare l'XML. Il vantaggio del DOM è che garantisce la validità XML; il vantaggio del motore di template è che si vede con un editor di testo che aspetto ha l'XML. Se si utilizza un motore di template, ricordare la corretta escaping delle variabili sostituite!

Avrai anche bisogno di una libreria JSON. Non ho ancora letto JSON in precedenza con Java; L'ho appena scritto (usando una libreria JSON personalizzata), quindi non so quali siano le tue opzioni. Sono abbastanza sicuro che tu sia in grado di trovare molte librerie JSON usando una semplice ricerca su Google.

Per indentare correttamente in DOM, fai questo:

TransformerFactory tf;
Transformer t;

tf = TransformerFactory.newInstance();
t = tf.newTransformer();
t.setOutputProperty(OutputKeys.INDENT, "yes");
t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");

... e quindi usa Transformer costruito per trasformare un documento XML in uno stream.

    
risposta data 27.07.2017 - 16:48
fonte
1

IMHO, il modo migliore sarebbe usare JAXB. Stai già convertendo il tuo JSON in POJO. Pertanto, se si dispone di uno schema (.xsd) a cui è conforme il proprio XML, è possibile utilizzare plugin maven per generare automaticamente DTO per JAXB e quindi utilizzare il marshalling per convertire POJO in XML.

Dal momento che i tuoi POJO sono diversi l'uno dall'altro, dovrai mapparli. Puoi utilizzare Dozer o qualsiasi altra strategia per eseguire lo stesso.

    
risposta data 27.07.2017 - 17:07
fonte
0

Can anyone recommend a solution for this last step? How to do this dynamically? Basically, I would like to map fields in my POJO with nodes in the XML file (also remembering that I need to keep that XML file external).

Ce l'hai quasi, non reinventare la ruota in questo ultimo passaggio.

Abbiamo qui due opzioni che, credo, sono compatibili con la tua strategia attuale. Templating e Evaluatori di espressioni .

Templating

Per quanto riguarda i modelli, Freemaker può svolgere il lavoro esattamente come desideri. Caricamento XML esterno come modello e sostituzione dei segnaposti da un POJO o da una mappa.

In sostanza, Freemaker valuta le espressioni. Quindi potresti andare direttamente alla soluzione alla ricerca degli analizzatori di espressioni Java più adatti alle tue esigenze.

Valutazione dell'espressione

Ad esempio, se hai Spring nello stack tecnologico, potresti essere interessato a Spring Expression , se non lo hai, MVEL -che sembra essere abbastanza conosciuto dalla comunità- potrebbe fare anche il lavoro.

String myXmlString = parser.parseExpression(
        "<MyTag><Tag>#{T(java.lang.Math).random()}</Tag></MyTag>",
        new TemplateParserContext()).getValue(String.class);

// <MyTag><Tag>0.7038186818312008</Tag></MyTag>

Inoltre

Per i binding di dati JSON più sofisticati, dai un'occhiata alle annotazioni di Jackson . Per quanto riguarda XML, binding di dati XML di Jackson , che fornisce anche annotazioni .

Un piccolo esempio di come associare i nodi XML e gli attributi JSON con nomi diversi allo stesso POJO

@JacksonXmlProperty(localName = "OnBoardingPending")
@JsonProperty(value = "on-boarding-pending", index = 1)
public int getOnBoardingPending() {
    return onBoardingPending;
}

@JacksonXmlProperty(localName = "NotActive")
@JsonProperty(value = "not-active", index = 2)
public int getNotActive() {
    return notActive;
}
    
risposta data 27.07.2017 - 23:49
fonte

Leggi altre domande sui tag