WSO2 ESB 无法将完整的 JSON 数据转换为 XML

Posted

技术标签:

【中文标题】WSO2 ESB 无法将完整的 JSON 数据转换为 XML【英文标题】:WSO2 ESB Unable to convert complete JSON data to XML 【发布时间】:2012-05-31 19:03:04 【问题描述】:

我正在构建 POC。我为 Google Plus 创建了一个直通代理服务。 在不使用任何代理服务的情况下,我得到了这是我的输出:

 
   "kind":"plus#person",
   "etag":"\"ExituU7aUpmkkfyD52VulzptThw/4J1clegrhxYC2fsJOu2XWCs1Ewg\"",
   "id":"117488614303967062311",
   "displayName":"Abhi NeoN",
   "name":
      "familyName":"NeoN",
      "givenName":"Abhi"
   ,
   "tagline":"hey guys ! ssup!! check out ma recnt videos... uploaded",
   "gender":"male",
   "aboutMe":"\u003cb\u003ehie, abhishek - ma full name \u003c/b\u003e\u003cdiv\u003e\u003cb\u003em a DANCER ,\u003c/b\u003e\u003c/div\u003e\u003cdiv\u003e\u003cb\u003ei luv ma dancing .\u003c/b\u003e\u003c/div\u003e\u003cdiv\u003e\u003cb\u003ei care ma dancing ,\u003c/b\u003e\u003c/div\u003e\u003cdiv\u003e\u003cb\u003ei jus hv a gr8 thng in me dats ma dancing.\u003c/b\u003e\u003c/div\u003e",
   "relationshipStatus":"single",
   "url":"https://plus.google.com/117488614303967062311",
   "image":
      "url":"https://lh6.googleusercontent.com/-tF-ip0tUxD4/AAAAAAAAAAI/AAAAAAAAAAA/WKI3USUh_DA/photo.jpg?sz=50"
   ,
   "urls":[
      
         "value":"https://plus.google.com/117488614303967062311",
         "type":"profile"
      ,
      
         "value":"https://www.googleapis.com/plus/v1/people/117488614303967062311",
         "type":"json"
      
   ],
   "organizations":[
      
         "name":"our lady of nazareth high school",
         "title":"science",
         "type":"school"
      ,
      
         "name":"",
         "title":"BLUEBYTES",
         "type":"work"
      
   ]

但是当我尝试使用简单的直通服务来做同样的事情时,我只得到:


   "kind":"plus#person"

我在 wso2esb 网站上读到他们有一个错误,解决错误的解释是收到的 json 数据格式不正确。 但是现在我该如何解决这个问题。我的意思是他们可以在 esb 将其转换为 json 数据之前以任何方式操作 json 数据。

【问题讨论】:

【参考方案1】:

我们已经在最新版本的 ESB(版本 4.5.0)中解决了这个问题。默认情况下,它带有 JSONMessageFormatter/JSONBuilder,可以处理带有多个键的 JSON 有效负载。

我们还提出了另一种解决方案,用于处理涉及不同类型的 JSON XML(或 JSON JSON)转换的消息流。 JSONStreamBuilderJSONStreamFormatter 可用于通过“脚本”中介实现此类场景。查看 ESB 4.5.0 中的示例 #441。

运行示例 #441;

添加 JSONStreamBuilderJSONStreamFormatter 作为构建器和 repository/conf/axis2/axis2.xml 文件中 JSON 的格式化程序 部署 SimpleStockQuoteService 启动示例axis2server 使用“ant newjsonclient”运行 JSON 客户端

【讨论】:

【参考方案2】:

这是当前axis2 JSON builder/formatter的限制之一。我们目前正在为 JSON 开发一个新的构建器/格式化器对,它不会转换 JSON XML。相反,它(构建器)将 JSON 消息存储为流,并且脚本中介可用于从该流构建 JSON 对象。例如,如果我们发送 "a" : "x", "b" : "y" 作为请求,在 ESB 中,我们可以使用 javascript 将此请求作为 JSON 对象进行操作。

var a = mc.getJSON().a.toString();
var b = mc.getJSON().b.toString();
mc.setPayloadXML(
    <m:A xmlns:m="http://example.json">
        <m:a>a</m:a>
        <m:b>b</m:b>
    </m:A>);

同样mc.setJSON() 方法可用于设置任意 JSON 对象。

【讨论】:

那么这是否意味着到目前为止我们没有任何其他解决方案来解决这个问题...?? 如果您不想在 ESB 中构建或操作消息,您可以使用消息中继消息构建器/格式化程序用于 application/json 来代替默认的轴 2 构建器/格式化程序对。看看this。 其实我修改了消息生成器的源代码,它至少现在解决了这个问题.. 我们使用了消息中继,但是它有一些实际问题:1)文本是base64编码的,所以我们不能在完整的日志中使用它。 2) 我们无法选择性地将服务从/到 JSON 转换,因为中继会获取所有应用程序/json。【参考方案3】:

可靠地将 json 转换为 xml 并再次转换回来的唯一方法是通过使用 xml 中的类型提示。默认转换器不这样做。它 1. 删除第一个属性之后的所有内容 2. 从xml到json时,将单个元素列表与属性混淆

我使用 json-util 库重新实现了转换类,它将 json 转换为包含类型提示作为元素属性的 xml,以确保没有歧义。

通过这种方式,我们可以毫无问题地通过 WSO2 为所有基于 json 的休息服务提供智能代理(即内容路由和调解传输和有效负载)

这样就解决了问题(我觉得camel默认是这样的)。

这里是pom文件和代码:

将 jar 放入 /repository/components/lib

您必须更新axis2.xml中内容类型“application/json”的messageformatter和messagebuilder映射


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <name>wso2 json/xml converter</name>
    <groupId>x.y.z</groupId>
    <artifactId>wso2converter</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <jdk.version>1.6</jdk.version>
    </properties>

    <build>
        <finalName>wso2converter</finalName>
        <resources>
            <resource>
                <filtering>false</filtering>
                <directory>src/main/resources</directory>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>$jdk.version</source>
                    <target>$jdk.version</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-enforcer-plugin</artifactId>
                <version>1.0.1</version>
                <executions>
                    <execution>
                        <id>enforce-jdk</id>
                        <phase>validate</phase>
                        <goals>
                            <goal>display-info</goal>
                            <goal>enforce</goal>
                        </goals>
                        <configuration>
                            <rules>
                                <requireJavaVersion>
                                    <version>[$jdk.version,)</version>
                                </requireJavaVersion>
                            </rules>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>net.sf.json-lib</groupId>
            <artifactId>json-lib</artifactId>
            <version>2.3</version>
            <classifier>jdk15</classifier>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.ws.commons.axiom</groupId>
            <artifactId>axiom-api</artifactId>
            <version>1.2.13</version>
        </dependency>

        <dependency>
            <groupId>org.apache.axis2</groupId>
            <artifactId>axis2-kernel</artifactId>
            <version>1.6.2</version>
        </dependency>

        <dependency>
            <groupId>xom</groupId>
            <artifactId>xom</artifactId>
            <version>1.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.synapse</groupId>
            <artifactId>synapse-core</artifactId>
            <version>2.1.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-json</artifactId>
            <version>1.1.5</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.2</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.13</version>
            <!--scope>provided</scope-->
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

</project>

package a.b.wso2;

import java.io.InputStream;
import net.sf.json.JSON;
import net.sf.json.JSONSerializer;
import net.sf.json.xml.XMLSerializer;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.util.AXIOMUtil;
import org.apache.axis2.AxisFault;
import org.apache.axis2.builder.Builder;
import org.apache.axis2.context.MessageContext;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;


public class WsoJtoX implements Builder 

    Logger logger = Logger.getLogger("a.b.wso2converter");

    @Override
    public OMElement processDocument(InputStream is, String contentType,
            MessageContext messageContext) throws AxisFault 
        String jsonData = "";
        try 

            jsonData = IOUtils.toString(is,"UTF-8");


            String output = process(jsonData);

            OMElement e = AXIOMUtil.stringToOM(output);
            return e;


         catch (Exception e) 
            logger.error("error converting json string " + jsonData, e);
            if (e instanceof AxisFault) 
                throw (AxisFault) e;
            
            throw new AxisFault("(B"+counter+") error converting json to xml", e);
        

    

    static int counter=0;

    public String process(String jsonData) throws AxisFault 

        try 
            String tran = "__ns__";

            jsonData=jsonData.replace("\r", "").trim();
            //jsonData=jsonData.replace("\n", "");

            String decoded = (jsonData.replaceAll("\"([a-zA-Z0-9_]*)\\:([a-zA-Z0-9]*)\"(\\s*)(:)", "\"$1" + tran + "$2\"$3:"));

            counter++;

            if (logger.isDebugEnabled()) 
                logger.debug("\n>>>>> (B"+counter+") converting json\n " + jsonData + "\n====");
            

            XMLSerializer serializer = new XMLSerializer();
            JSON json = JSONSerializer.toJSON(decoded);

            String xml = serializer.write(json);

            //add in the soap stuff
            StringBuilder sb = new StringBuilder();
            sb.append("<soap:Envelope xmlns:soap=\"http://www.w3.org/2001/12/soap-envelope\" soap:encodingStyle=\"http://www.w3.org/2001/12/soap-encoding\"> <soap:Body>");
            sb.append(xml.replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>", ""));
            sb.append("</soap:Body></soap:Envelope>");

            if (logger.isDebugEnabled()) 
                logger.debug("\n==== (B"+counter+") to xml\n" + sb.toString()+"\n<<<<<");
            

            return sb.toString();


         catch (Exception e) 
            throw new AxisFault("(B"+counter+") error transforming json to xml", e);
        

    



package a.b.wso2;

import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import net.sf.json.JSON;

import net.sf.json.xml.XMLSerializer;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMOutputFormat;
import org.apache.axiom.om.util.AXIOMUtil;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.transport.MessageFormatter;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;

public class WsoXtoJ implements MessageFormatter 

    Logger logger = Logger.getLogger("a.b.wso2converter");

    private static int counter=0;

    public String convert(String xData) 

        counter++;

            if (logger.isDebugEnabled()) 
                logger.debug("\n]]]]] (A"+counter+") converting xml\n " + xData + "\n-----");
            


        try 
            String tran = "__ns__";
            XMLSerializer serializer = new XMLSerializer();
            OMElement e = AXIOMUtil.stringToOM(xData);
            OMElement b = (OMElement) e.getChildrenWithLocalName("Body").next();
            b = (OMElement) b.getChildElements().next();
            String xfrag = b.toStringWithConsume();
            String str = "";
            JSON j = serializer.read(xfrag);
            str = j.toString();
            String nstr = str.replaceAll("\"([a-zA-Z0-9_]+)" + tran + "([a-zA-Z0-9]+)\"(\\s*)(:)", "\"$1:$2\"$3:");  //", "\"$1:$2\"");

            if (logger.isDebugEnabled()) 
                logger.debug("\n----- (A"+counter+") to json\n" + nstr+"\n[[[[[");
            

            return nstr;

         catch (Exception e) 
            throw new RuntimeException(e);
        

    

    @Override
    public String formatSOAPAction(MessageContext msgCtxt, OMOutputFormat format,
            String soapActionString) 
        return null;
    

    @Override
    public byte[] getBytes(MessageContext ctx, OMOutputFormat format)
            throws AxisFault 
        String env="";
        try 
            OMElement element = ctx.getEnvelope().getBody().getFirstElement();
            String payload = this.convert(element.toString());
            return payload.getBytes(format.getCharSetEncoding());
         catch (UnsupportedEncodingException e) 
            logger.error("(A"+counter+") error converting xml to json "+ctx.getEnvelope().toString());
            throw AxisFault.makeFault(e);
        
    

    @Override
    public String getContentType(MessageContext msgCtxt, OMOutputFormat format,
            String soapActionString) 
        String contentType = (String) msgCtxt.getProperty(Constants.Configuration.CONTENT_TYPE);
        String encoding = format.getCharSetEncoding();
        if (contentType == null) 
            contentType = (String) msgCtxt.getProperty(Constants.Configuration.MESSAGE_TYPE);
        
        if (encoding != null) 
            contentType += "; charset=" + encoding;
        
        return contentType;
    

    @Override
    public URL getTargetAddress(MessageContext msgCtxt, OMOutputFormat format,
            URL targetURL) throws AxisFault 
        return targetURL;
    

    @Override
    public void writeTo(MessageContext msgCtxt, OMOutputFormat format,
            OutputStream out, boolean preserve) throws AxisFault 
        try 
            out.write(this.getBytes(msgCtxt, format));
            out.flush();
         catch (IOException e) 
            throw AxisFault.makeFault(e);
        
    


【讨论】:

【参考方案4】:

我遇到了同样的问题。

根据我的经验,WSO2 ESB(基于 Axis2-json)的 JSON 解析器仅支持 JSON 的一个子集:

    JSON 必须以“”开头,即根不能有 JSONArray。

    只考虑第一个键值对。这是因为 JSON 映射到类似 XML 的数据结构,而 XML 必须有根,所以第一个键值对被认为是根。

    第一个键值对的值不能是数组。这是因为转换器必须知道每个值应该使用哪个 XML 标记:

    例如:... "key": ["val1", "val2", ...] -> val1val2....

我在这里遇到了同样的问题,想找到解决办法。我的想法是创建一个新的 JSONBuilder(构建内部 SOAP 消息构造的解析器)和 JSONFormatter(序列化器)以使用虚拟根(例如 "root" : ... )伪造解析器。

【讨论】:

以上是关于WSO2 ESB 无法将完整的 JSON 数据转换为 XML的主要内容,如果未能解决你的问题,请参考以下文章

WSO2:将CSV消息转换为json wso2 esb。在prolog中出现意外字符'“'(代码34)失败;预期'

WSO2:wso2中的xml到json数据映射esb:json消息包含在soap信封中

为什么在WSO2 ESB中我无法创建一个新属性,它是另一个属性和固定字符串的串联?我得到null作为结果

WSO2 ESB 5.0.0 一些组件的使用教程

WSO2 ESB 5.0.0 一些组件的使用教程

为什么JSON路径无效为WSO2 ESB 5.0的JSON请求