WSO2 ESB:如何从嵌套迭代器聚合有效负载
WSO2 ESB: How to Aggregate Payloads from Nested Iterators
我正在尝试从 Facebook 页面生成评论流。最后,我希望 WSO2 能像这样回应:
<comments>
<comment>
<post_id>123</post_id>
<comment_id>456</comment_id>
<from_name>Bob Brown</from_name>
<from_id>789</from_id>
<message>This is a comment on a post.</message>
<created_time>2015-12-17T15:25:30+0000</created_time>
</comment>
</comments>
我正在使用 WSO2 ESB 的 API 模块在 Facebook 页面上提供抽象层,以获取给定时间戳后页面上所有评论的简单流。
我现在正在处理的逻辑是获取给定 Facebook 页面上的所有 posts(使用 WSO2 Facebook Connector),遍历所有 posts(使用迭代中介),检查 post 是否有评论(使用过滤器中介),如果有评论,我将迭代评论并将它们重组为一个简单的 XML 元素(使用 PayloadFactory 中介) ).这就是我卡住的地方。
我发现在迭代调解器中我无法更新迭代器外部的属性。我最初的直觉是用第二个迭代器中生成的评论有效负载作为子元素来丰富外部 属性,但没有骰子。
我现在正尝试聚合第二个迭代器的输出,如下所示,但我无法聚合有效负载:
<?xml version="1.0" encoding="UTF-8"?>
<inSequence xmlns="http://ws.apache.org/ns/synapse">
<property expression="$ctx:query.param.limit" name="limit"
scope="default" type="STRING"/>
<property expression="$ctx:query.param.since" name="since"
scope="default" type="STRING"/>
<property name="fields" scope="default" type="STRING" value="id,comments{id,message,from,created_time}"/>
<call-template target="facebook_getFeed">
<with-param name="pageId" value="{get-property('uri.var.page')}"/>
<with-param name="maxPosts" value="{get-property('limit')}"/>
<with-param name="since" value="{get-property('since')}"/>
<with-param name="fields" value="{get-property('fields')}"/>
</call-template>
<log level="custom">
<property name="S3_MESSAGE" value="Iterating through posts"/>
</log>
<property name="comment_stream" scope="default">
<comments xmlns=""/>
</property>
<iterate continueParent="true" expression="//jsonObject/data"
id="fb_api_comments_post_iterate" sequential="true" xmlns:ns1="http://cache.services">
<target>
<sequence>
<filter xmlns:ns="http://org.apache.synapse/xsd" xpath="count(//data/comments)>0">
<then>
<property expression="//data/id"
name="fb_post_id" scope="operation" type="STRING"/>
<iterate continueParent="true"
expression="//data/comments/data"
id="fb_api_comments_comment_iterate" sequential="true">
<target>
<sequence>
<log level="custom">
<property name="S3_MESSAGE" value="Transforming comment"/>
</log>
<payloadFactory media-type="xml">
<format>
<comments xmlns="">
<post_id></post_id>
<comment_id></comment_id>
<from_name></from_name>
<from_id></from_id>
<message></message>
<created_time></created_time>
</comments>
</format>
<args>
<arg evaluator="xml" expression="get-property('fb_post_id')"/>
<arg evaluator="xml" expression="//data/id"/>
<arg evaluator="xml" expression="//data/from/name"/>
<arg evaluator="xml" expression="//data/from/id"/>
<arg evaluator="xml" expression="//data/message"/>
<arg evaluator="xml" expression="//data/created_time"/>
</args>
</payloadFactory>
</sequence>
</target>
</iterate>
</then>
</filter>
</sequence>
</target>
</iterate>
<aggregate>
<correlateOn expression="fb_api_comments_comment_iterate"/>
<completeCondition>
<messageCount max="-1" min="-1"/>
</completeCondition>
<onComplete enclosingElementProperty="comment_stream" expression="//comments">
<loopback/>
</onComplete>
</aggregate>
</inSequence>
如有任何帮助,我们将不胜感激。
虽然我很高兴有人 post 技术上 更正确 回答,但由于时间有限,我硬着头皮写了一些随意 JavaScript 在脚本中介中:
var payload = mc.getPayloadXML();
print("Starting FB Post Loop...");
var comments = new XML("<comments></comments>");
comments.comment = new XMLList();
for (var i = 0; i < payload[0].data.length(); i++){
print("Checking if post has comments...");
if(payload[0].data[i].comments.data.length() > 0){
print("Comments exist on this post...");
print("Post ID: " + payload[0].data[i].id);
for (var ii = 0; ii < payload[0].data[i].comments.data.length(); ii++){
print("Building comment entry...");
var comment = <comment/>;
comment.post_id = payload[0].data[i].id.toString();
comment.comment_id = payload[0].data[i].comments.data[ii].id.toString();
comment.from_id = payload[0].data[i].comments.data[ii].from.id.toString();
comment.from_name = payload[0].data[i].comments.data[ii].from.name.toString();
comment.message = payload[0].data[i].comments.data[ii].message.toString();
comment.created_time = payload[0].data[i].comments.data[ii].created_time.toString();
print(comment);
comments.comment += comment;
}
}
}
mc.setPayloadXML(comments);
恕我直言,不得不回退到自定义代码很好,但从可维护性的角度来看,这通常意味着一个世界的伤害。硬币的另一面是,我真的很想尽可能地利用 WSO2/Synapse 调解器,因为这就是使用 WSO2 ESB 的意义所在!
期待 reading/discussing 其他解决方案。
在您的问题中,您提到 属性 更新不在迭代调解器范围内。据我所知,这是由于这个原因而发生的。
在调用每个迭代循环之前,将克隆消息上下文,并且它仅在迭代器目标内的上下文中可用。因此,我们无法在 default/synapse 范围内的迭代器中更新 messages/properties 。如果要存储全局内容,请使用 属性 和 operation scope。
这个问题是怎么解决的,
- 在迭代器之前 - 将 属性 分配给操作范围
- 内部迭代器 - 进行修改
- 在迭代器之外 - 将 属性 分配给默认范围(如果您
想把它恢复到默认范围)
使用以下结构作为代理服务的示例:
<!--assign the property to operation scope-->
<property name="ITERATOR_DATA_PAYLOAD"
expression="get-property('DATA_PAYLOAD')"
scope="operation"
type="OM"/>
<iterate xmlns:ns="http://org.apache.synapse/xsd"
continueParent="true"
expression="//bookstore/book"
sequential="true">
<target>
<sequence>
<!--if want to assign the property-->
<property name="DATA_PAYLOAD"
expression="get-property('operation','ITERATOR_DATA_PAYLOAD')"
type="OM"/>
</sequence>
</target>
</iterate>
<!--Outside the iterator-->
<property xmlns:ns="http://org.apache.synapse/xsd"
name="NEW_DATA_PAYLOAD"
expression="get-property('operation','ITERATOR_DATA_PAYLOAD')"
type="OM"/>
我正在尝试从 Facebook 页面生成评论流。最后,我希望 WSO2 能像这样回应:
<comments>
<comment>
<post_id>123</post_id>
<comment_id>456</comment_id>
<from_name>Bob Brown</from_name>
<from_id>789</from_id>
<message>This is a comment on a post.</message>
<created_time>2015-12-17T15:25:30+0000</created_time>
</comment>
</comments>
我正在使用 WSO2 ESB 的 API 模块在 Facebook 页面上提供抽象层,以获取给定时间戳后页面上所有评论的简单流。
我现在正在处理的逻辑是获取给定 Facebook 页面上的所有 posts(使用 WSO2 Facebook Connector),遍历所有 posts(使用迭代中介),检查 post 是否有评论(使用过滤器中介),如果有评论,我将迭代评论并将它们重组为一个简单的 XML 元素(使用 PayloadFactory 中介) ).这就是我卡住的地方。
我发现在迭代调解器中我无法更新迭代器外部的属性。我最初的直觉是用第二个迭代器中生成的评论有效负载作为子元素来丰富外部 属性,但没有骰子。
我现在正尝试聚合第二个迭代器的输出,如下所示,但我无法聚合有效负载:
<?xml version="1.0" encoding="UTF-8"?>
<inSequence xmlns="http://ws.apache.org/ns/synapse">
<property expression="$ctx:query.param.limit" name="limit"
scope="default" type="STRING"/>
<property expression="$ctx:query.param.since" name="since"
scope="default" type="STRING"/>
<property name="fields" scope="default" type="STRING" value="id,comments{id,message,from,created_time}"/>
<call-template target="facebook_getFeed">
<with-param name="pageId" value="{get-property('uri.var.page')}"/>
<with-param name="maxPosts" value="{get-property('limit')}"/>
<with-param name="since" value="{get-property('since')}"/>
<with-param name="fields" value="{get-property('fields')}"/>
</call-template>
<log level="custom">
<property name="S3_MESSAGE" value="Iterating through posts"/>
</log>
<property name="comment_stream" scope="default">
<comments xmlns=""/>
</property>
<iterate continueParent="true" expression="//jsonObject/data"
id="fb_api_comments_post_iterate" sequential="true" xmlns:ns1="http://cache.services">
<target>
<sequence>
<filter xmlns:ns="http://org.apache.synapse/xsd" xpath="count(//data/comments)>0">
<then>
<property expression="//data/id"
name="fb_post_id" scope="operation" type="STRING"/>
<iterate continueParent="true"
expression="//data/comments/data"
id="fb_api_comments_comment_iterate" sequential="true">
<target>
<sequence>
<log level="custom">
<property name="S3_MESSAGE" value="Transforming comment"/>
</log>
<payloadFactory media-type="xml">
<format>
<comments xmlns="">
<post_id></post_id>
<comment_id></comment_id>
<from_name></from_name>
<from_id></from_id>
<message></message>
<created_time></created_time>
</comments>
</format>
<args>
<arg evaluator="xml" expression="get-property('fb_post_id')"/>
<arg evaluator="xml" expression="//data/id"/>
<arg evaluator="xml" expression="//data/from/name"/>
<arg evaluator="xml" expression="//data/from/id"/>
<arg evaluator="xml" expression="//data/message"/>
<arg evaluator="xml" expression="//data/created_time"/>
</args>
</payloadFactory>
</sequence>
</target>
</iterate>
</then>
</filter>
</sequence>
</target>
</iterate>
<aggregate>
<correlateOn expression="fb_api_comments_comment_iterate"/>
<completeCondition>
<messageCount max="-1" min="-1"/>
</completeCondition>
<onComplete enclosingElementProperty="comment_stream" expression="//comments">
<loopback/>
</onComplete>
</aggregate>
</inSequence>
如有任何帮助,我们将不胜感激。
虽然我很高兴有人 post 技术上 更正确 回答,但由于时间有限,我硬着头皮写了一些随意 JavaScript 在脚本中介中:
var payload = mc.getPayloadXML();
print("Starting FB Post Loop...");
var comments = new XML("<comments></comments>");
comments.comment = new XMLList();
for (var i = 0; i < payload[0].data.length(); i++){
print("Checking if post has comments...");
if(payload[0].data[i].comments.data.length() > 0){
print("Comments exist on this post...");
print("Post ID: " + payload[0].data[i].id);
for (var ii = 0; ii < payload[0].data[i].comments.data.length(); ii++){
print("Building comment entry...");
var comment = <comment/>;
comment.post_id = payload[0].data[i].id.toString();
comment.comment_id = payload[0].data[i].comments.data[ii].id.toString();
comment.from_id = payload[0].data[i].comments.data[ii].from.id.toString();
comment.from_name = payload[0].data[i].comments.data[ii].from.name.toString();
comment.message = payload[0].data[i].comments.data[ii].message.toString();
comment.created_time = payload[0].data[i].comments.data[ii].created_time.toString();
print(comment);
comments.comment += comment;
}
}
}
mc.setPayloadXML(comments);
恕我直言,不得不回退到自定义代码很好,但从可维护性的角度来看,这通常意味着一个世界的伤害。硬币的另一面是,我真的很想尽可能地利用 WSO2/Synapse 调解器,因为这就是使用 WSO2 ESB 的意义所在!
期待 reading/discussing 其他解决方案。
在您的问题中,您提到 属性 更新不在迭代调解器范围内。据我所知,这是由于这个原因而发生的。
在调用每个迭代循环之前,将克隆消息上下文,并且它仅在迭代器目标内的上下文中可用。因此,我们无法在 default/synapse 范围内的迭代器中更新 messages/properties 。如果要存储全局内容,请使用 属性 和 operation scope。
这个问题是怎么解决的,
- 在迭代器之前 - 将 属性 分配给操作范围
- 内部迭代器 - 进行修改
- 在迭代器之外 - 将 属性 分配给默认范围(如果您 想把它恢复到默认范围)
使用以下结构作为代理服务的示例:
<!--assign the property to operation scope-->
<property name="ITERATOR_DATA_PAYLOAD"
expression="get-property('DATA_PAYLOAD')"
scope="operation"
type="OM"/>
<iterate xmlns:ns="http://org.apache.synapse/xsd"
continueParent="true"
expression="//bookstore/book"
sequential="true">
<target>
<sequence>
<!--if want to assign the property-->
<property name="DATA_PAYLOAD"
expression="get-property('operation','ITERATOR_DATA_PAYLOAD')"
type="OM"/>
</sequence>
</target>
</iterate>
<!--Outside the iterator-->
<property xmlns:ns="http://org.apache.synapse/xsd"
name="NEW_DATA_PAYLOAD"
expression="get-property('operation','ITERATOR_DATA_PAYLOAD')"
type="OM"/>