【问题标题】:Mule ESB 3.6 Object To XML not working correctly after Database Connector数据库连接器后 Mule ESB 3.6 Object To XML 无法正常工作
【发布时间】:2015-07-21 21:16:14
【问题描述】:

我是 Mule ESB (3.6) 的新手,正在测试一个简单的流程来从 MS SQL Server Express DB 中检索记录,并使用“Object to XML”转换器将结果转换为 XML。

“客户”表只有 2 行,我的查询只是返回数据库中的所有字段。

我的问题:返回的 XML 不是我所期望的(基于链表映射,而不是基于查询的 XML 结构)。如果我将转换器替换为“Object to JSON”版本,则返回的 JSON 仅代表查询结果(这是我所期望的)。

我遵循了许多在线教程,并且没有提到任何额外的设置/值适用于对象到 XML 转换器(所以假设应用默认值)。

这是一个错误还是我需要在某处应用更多设置?

我的流程的 XML

<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:json="http://www.mulesoft.org/schema/mule/json" xmlns:data-mapper="http://www.mulesoft.org/schema/mule/ee/data-mapper" xmlns:file="http://www.mulesoft.org/schema/mule/file" xmlns:mulexml="http://www.mulesoft.org/schema/mule/xml" xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:db="http://www.mulesoft.org/schema/mule/db" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xmlns:spring="http://www.springframework.org/schema/beans" version="EE-3.6.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd

http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/db http://www.mulesoft.org/schema/mule/db/current/mule-db.xsd
http://www.mulesoft.org/schema/mule/ee/data-mapper http://www.mulesoft.org/schema/mule/ee/data-mapper/current/mule-data-mapper.xsd
http://www.mulesoft.org/schema/mule/xml http://www.mulesoft.org/schema/mule/xml/current/mule-xml.xsd
http://www.mulesoft.org/schema/mule/file http://www.mulesoft.org/schema/mule/file/current/mule-file.xsd
http://www.mulesoft.org/schema/mule/json http://www.mulesoft.org/schema/mule/json/current/mule-json.xsd">
<http:listener-config name="HTTP_Listener_Configuration" host="0.0.0.0" port="8081" basePath="/DBQuery" doc:name="HTTP Listener Configuration"/>
    <db:generic-config name="Generic_Database_Configuration" url="jdbc:sqlserver://xxxx;databaseName=xxxx;user=xxxx;password=xxxx" doc:name="Generic Database Configuration" driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<file:connector name="File" outputPattern="#[server.dateTime.format(&quot;yyyyMMdd'T'HHmmss.SSS&quot;)].xml" autoDelete="true" streaming="true" validateConnections="true" doc:name="File"/>
<flow name="dbqueryFlow">
    <http:listener config-ref="HTTP_Listener_Configuration" path="/" doc:name="HTTP"/>
    <db:select config-ref="Generic_Database_Configuration" doc:name="Database ">
<db:parameterized-query><![CDATA[SELECT CustomerNumber
  ,CustomerName
  ,CustomerAddressLine1
  ,CustomerAddressLine2
  ,CustomerSuburb
  ,CustomerStateName
  ,CustomerPostcode
  FROM Customer]]>
</db:parameterized-query>
</db:select>
    <mulexml:object-to-xml-transformer encoding="UTF-8" mimeType="text/xml" doc:name="Object to XML"/>
    <file:outbound-endpoint path="C:\Mule\DBQuery\Backup" connector-ref="File" responseTimeout="10000" doc:name="File"/>
    <logger level="INFO" doc:name="Logger" message="#[payload]"/>
</flow>

返回的 XML

<linked-list>
  <org.mule.util.CaseInsensitiveHashMap serialization="custom">
    <unserializable-parents/>
    <org.mule.util.CaseInsensitiveHashMap>
      <default/>
      <float>0.75</float>
      <int>16</int>
      <int>7</int>
      <string>CustomerNumber</string>
      <string>1                                       </string>
      <string>CustomerSuburb</string>
      <string>Mt Eliza                                </string>
      <string>CustomerStateName</string>
      <string>Victoria                                </string>
      <string>CustomerAddressLine1</string>
      <string>Street name                                                                                         </string>
      <string>CustomerPostcode</string>
      <string>3930      </string>
      <string>CustomerAddressLine2</string>
      <string>                                                                                                    </string>
      <string>CustomerName</string>
      <string>Sarge                                                                                               </string>
    </org.mule.util.CaseInsensitiveHashMap>
  </org.mule.util.CaseInsensitiveHashMap>
  <org.mule.util.CaseInsensitiveHashMap serialization="custom">
    <unserializable-parents/>
    <org.mule.util.CaseInsensitiveHashMap>
      <default/>
      <float>0.75</float>
      <int>16</int>
      <int>7</int>
      <string>CustomerNumber</string>
      <string>2                                       </string>
      <string>CustomerSuburb</string>
      <string>Balwyn                                  </string>
      <string>CustomerStateName</string>
      <string>Victoria                                </string>
      <string>CustomerAddressLine1</string>
      <string>Street     name                                                                                         </string>
      <string>CustomerPostcode</string>
      <string>3920      </string>
      <string>CustomerAddressLine2</string>
      <string>                                                                                                    </string>
      <string>CustomerName</string>
      <string>Daniel                                                                                              </string>
    </org.mule.util.CaseInsensitiveHashMap>
  </org.mule.util.CaseInsensitiveHashMap>
</linked-list>

JSON 返回(仅 DB 字段 - 这是我所期望的)

[{"CustomerNumber":"1                                             ","CustomerSuburb":"Mt Eliza                                ","CustomerStateName":"Victoria                                ","CustomerAddressLine1":"Street name                                                                                         ","CustomerPostcode":"3930      ","CustomerAddressLine2":"                                                                                                    ","CustomerName":"Sarge                                                                                               "},{"CustomerNumber":"2                                       ","CustomerSuburb":"Balwyn                                  ","CustomerStateName":"Victoria                                ","CustomerAddressLine1":"Street name                                                                                         ","CustomerPostcode":"3920      ","CustomerAddressLine2":"                                                                                                    ","CustomerName":"Daniel                                                                                              "}]

另外,如何从输出中删除尾随空格?

谢谢 大卫

【问题讨论】:

  • Mmhh 我已经尝试过解决这个问题,但看起来只有构建自己的自定义转换器类才能获得干净的 XML。如果不是问题,我会建议坚持使用 JSON。关于空格:看起来它们在您的数据库记录中。你能检查一下吗?如果是这种情况,您可以在查询中使用 SQL Server 的TRIM 函数。
  • 谢谢马蒂洛。你知道我可以遵循的任何 URL 来构建我自己的类吗(我不是 Java 专家)。使用 TRIM 函数,我尝试使用它,但从 JDBC 驱动程序中获取元数据检索错误(com.microsoft.sqlserver.jdbc.SQLServerException: A processing error "'TRIM' is not a known built-in function name." 发生): -)
  • RTRIM 函数有效,但我必须在每个字段之后添加“as ”(否则会收到运行流程的错误)。

标签: xml mule mule-studio


【解决方案1】:

一个选项可以使用自定义转换器。

有一些方法可以编写自定义转换器。在下面的代码中,我使用的是从 AbstractTransformer 扩展的,它提供了带有 2 个参数的 doTransform 方法。第一个是source,第二个是encoding。如果您想处理流程中上一步的数据,请使用src

自定义转换器:

public class ContactsBundleTransformer extends AbstractTransformer {

    @SuppressWarnings("unchecked")
    @Override
    protected Object doTransform(Object src, String enc)
            throws TransformerException {    
        return null;
    }

}

注册自定义转换器,以使转换器在您的流程中可用:

<spring:beans>
    <spring:bean id="contactsBundleTransformer" name="contactsBundleTransformer" class="io.eddumelendez.xml.ContactsBundleTransformer"/>
</spring:beans>

在您的流程中,您必须参考自定义转换器。您可以查看下面的示例。

流程:

<flow name="demoFlow">
        <http:listener config-ref="HTTP_Listener_Configuration" path="/" doc:name="HTTP"/>
        <db:select config-ref="MySQL_Configuration" doc:name="Database" >
            <db:parameterized-query><![CDATA[select node_id, bundle_data from pm_contacts_bundle]]></db:parameterized-query>
        </db:select>
        <logger message="#[payload]" level="INFO" doc:name="Logger"/>
        <transformer ref="contactsBundleTransformer" doc:name="Transformer Reference"/>
        <mulexml:object-to-xml-transformer doc:name="Object to XML"/>
        <logger message="#[payload]" level="INFO" doc:name="Logger"/>

</flow>

【讨论】:

  • 您好 Eddu,感谢您的 cmets。我试了一下,但没有任何运气。我已经用详细信息编辑了我的原始帖子。我做错了什么?
  • 别担心,解决了!字符串的返回类型成功了!
【解决方案2】:

成功了!

经过大量的折腾(以及使用 Java 学习 XML 的速成课程)并阅读了 Eddu 上面的帖子,我能够创建一个自定义转换器。

在我的流程中将“Object to XML”转换器更改为“Java”转换器。 创建了 SQLCustomerToXML 类(确保返回类型为 String)。

变压器

import java.io.StringWriter;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.mule.api.transformer.TransformerException;
import org.mule.transformer.AbstractTransformer;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class SQLCustomerToXML extends AbstractTransformer {

    @SuppressWarnings("unchecked")
    @Override
    protected Object doTransform(Object src, String enc)
        throws TransformerException {

    List<Map<String, Object>> list = (List<Map<String, Object>>) src;
    Document doc;

    try {

        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();

        // root elements
        doc = docBuilder.newDocument();
        Element rootElement = doc.createElement("Customers");
        doc.appendChild(rootElement);

        for (Map<String, Object> map : list) {
            // New Customer Entry
            logger.info("Customer:");
            Element customerElement = doc.createElement("Customer");
            rootElement.appendChild(customerElement);

            // Each entry in Map for Customer
            for (Map.Entry<String, Object> element : map.entrySet()) {
                logger.info("   " + element.getKey() + ":" + element.getValue().toString());
                Element e = doc.createElement(element.getKey());
                e.setTextContent(element.getValue().toString());
                customerElement.appendChild(e);
            }
        }

        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        DOMSource source = new DOMSource(doc);

        // Write XML to String
        StringWriter writer = new StringWriter();
        StreamResult result = new StreamResult(writer);
        transformer.transform(source, result);

        logger.info("XML : " + writer.toString());

        return writer.toString();

      } catch (ParserConfigurationException pce) {
        pce.printStackTrace();
      } catch (Exception e) {
        e.printStackTrace();
      }

    return null;
    }
}

Java 转换器设置

<custom-transformer returnClass="java.lang.String" encoding="UTF-8" mimeType="text/xml" class="SQLCustomerToXML" doc:name="Java"/> 

XML 结果(在文件和浏览器中)

<?xml version="1.0" encoding="UTF-8"?>
<Customers>
    <Customer>
        <CustomerNumber>1</CustomerNumber>
        <CustomerSuburb>Mt Eliza</CustomerSuburb>
        <CustomerStateName>Victoria</CustomerStateName>
        <CustomerAddressLine1>Street name</CustomerAddressLine1>
        <CustomerPostcode>3930</CustomerPostcode>
        <CustomerAddressLine2 />
        <CustomerName>Sarge</CustomerName>
    </Customer>
    <Customer>
        <CustomerNumber>2</CustomerNumber>
        <CustomerSuburb>Balwyn</CustomerSuburb>
        <CustomerStateName>Victoria</CustomerStateName>
        <CustomerAddressLine1>Street name</CustomerAddressLine1>
        <CustomerPostcode>3920</CustomerPostcode>
        <CustomerAddressLine2 />
        <CustomerName>Daniel</CustomerName>
    </Customer>
</Customers>

大卫

【讨论】:

    【解决方案3】:

    感谢 David McInnes,您拯救了我的一天。 在 e.setTextContent() 中处理 Null 异常的代码的小改进。

    import java.io.StringWriter;
    import java.util.List;
    import java.util.Map;
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import javax.xml.parsers.ParserConfigurationException;
    import javax.xml.transform.Transformer;
    import javax.xml.transform.TransformerFactory;
    import javax.xml.transform.dom.DOMSource; 
    import javax.xml.transform.stream.StreamResult;
    import org.mule.api.transformer.TransformerException;
    import org.mule.transformer.AbstractTransformer;
    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    
    public class SQLCustomerToXML extends AbstractTransformer {
    
    @SuppressWarnings("unchecked")
    @Override
    protected Object doTransform(Object src, String enc)
        throws TransformerException {
    
    List<Map<String, Object>> list = (List<Map<String, Object>>) src;
    Document doc;
    
    try {
    
        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
    
        // root elements
        doc = docBuilder.newDocument();
        Element rootElement = doc.createElement("Customers");
        doc.appendChild(rootElement);
    
        for (Map<String, Object> map : list) {
            // New Customer Entry
            logger.info("Customer:");
            Element customerElement = doc.createElement("Customer");
            rootElement.appendChild(customerElement);
    
            // Each entry in Map for Customer
            for (Map.Entry<String, Object> element : map.entrySet()) {
               //  logger.info("   " + element.getKey() + ":" + element.getValue().toString());  // This will throw error if value is null
                Element e = doc.createElement(element.getKey());
                if (element.getValue() != null) {
                    e.setTextContent(element.getValue().toString());
                } else {
                    e.setTextContent("null");
                }   
                e.setTextContent(element.getValue().toString());
                customerElement.appendChild(e);
            }
        }
    
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        DOMSource source = new DOMSource(doc);
    
        // Write XML to String
        StringWriter writer = new StringWriter();
        StreamResult result = new StreamResult(writer);
        transformer.transform(source, result);
    
        logger.info("XML : " + writer.toString());
    
        return writer.toString();
    
      } catch (ParserConfigurationException pce) {
        pce.printStackTrace();
      } catch (Exception e) {
        e.printStackTrace();
      }
    
    return null;
    }   }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-14
      • 2016-06-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多