没有人能一次做好所有的事情,也不可能有一套系统收尽所有资料。既然如此,如何适当且适时的抓取外部资料做为己用,是一件很重要的事情。
近年来除许多资料以 OPEN DATA形式提供公众使用;编程也纷纷将程序打散,做得更细更专,推行『微服务』化。今天篇章先不论怎麽写出服务,而先探讨如何调取别人的服务。
一般外部资料提供有透过 API取用或实体档案抓取,实体档案可透过 wget 取回後用前述章节的channel解读。API的部分,通常在回传值还可区分为CSV / XML / JSON等等格式。今天范例取用日常生活可能会用到的『中油油价表』作为范例:
参考网址 https://data.gov.tw/dataset/6339
从范例中可得知,调用後会以 XML 格式回传,因此依循Genero 方式拆解。所以为了阅读方便,程序拆成两段
Genero FGL要串接外部现成已经提供的服务并不困难,我们这次的目标是取回下列格式资料
从最简单的调用范例来解读:
PUBLIC FUNCTION FetchCPCPrice()
DEFINE ok BOOLEAN
DEFINE req com.HttpRequest #取用WebService主要物件
DEFINE resp com.HttpResponse #分析回传资料使用
DEFINE resptype STRING
DEFINE doc xml.DomDocument #抓出的XML Document
DEFINE node xml.DomNode #在Genero中基本转为DomNode可用的method较多
DEFINE str STRING
DEFINE ind INTEGER
DEFINE baseURL STRING
#中油牌价服务路径
LET baseURL = "https://vipmember.tmtd.cpc.com.tw/opendata/",
"ListPriceWebService.asmx/getCPCMainProdListPrice_XML"
LET req = com.HttpRequest.Create(baseURL) #准备连结
CALL req.setMethod("GET") #使用 GET 方法 (还有POST.DELETE..等)
CALL req.doRequest() #做
LET resp = req.getResponse() #将回应写入Response物件, 等待分析
IF resp.getStatusCode()==200 THEN #状态码检查
LET resptype = resp.getHeader("Content-Type") #准备确认一下形式是否正确
IF resptype.getIndexOf("/xml",1) THEN #检查是否为 XML
LET doc = resp.getXmlResponse() #使用XML获取资料
LET node = doc.getDocumentElement() #转换为Genero xml.Document格式
END IF
LET ok = TRUE
ELSE
LET ok = FALSE
END IF
RETURN ok, str, node
END FUNCTION
Genero为了不让套件过大,将回传分析的功能(method)放进了HTTPResponse,所以在取用 Web Service之後,再调取Response处理就好。
分类:使用前,在程序最前端需 IMPORT com
功能:创建连结物件,并依照提供服务端的要求,可对本次发起的服务做好行前准备。如告知使用方法、放入参数、设定封包表头、设定TIMEOUT时间、与Cookie, proxy 等。接着就可依照不同的方式,做 Request(一般) / FileRquest / DataRequest / XmlRequest 等等。
Method List
特别注意:
分类:使用前,在程序最前端需 IMPORT com
功能:完成 WebService调用後,取回的状态与成果分析使用
Method List
特别注意:
先阅读一下范例
IMPORT xml
IMPORT com
###需使用到的extension包###
MAIN
DEFINE str,tagname,value STRING
DEFINE ok,i,cnt INTEGER
DEFINE r,every,child xml.DomNode
DEFINE n xml.DomNodeList
CALL FetchCPCPrice() RETURNING ok, str, r #前段WEB Service调用回传
IF ok THEN
# 预期要处理的格式如下:
#<Table>
# <型别名称>汽柴油零售</型别名称>
# <产品名称>92无铅汽油</产品名称>
# <参考牌价>28.2</参考牌价>
#</Table> #思路: 找出Table节点, 再往下找出型别,产品,牌价等
LET n = r.selectByXPath("Table",NULL) #利用SELECT BY X(ML) PATH找符合条件的清单
LET cnt = n.getCount() #确认符合数
FOR i=1 TO cnt
LET every = n.getItem(i) #取用个别的下层结构
LET child = every.getFirstChild() #往下一层进入
WHILE (child IS NOT NULL)
LET tagname = child.getNodeName() #只处理对的子项目
IF tagname = "型别名称" OR tagname = "产品名称" OR tagname = "参考牌价" THEN
LET value = child.toString()
LET value = value.subString(value.getIndexOf(">",1)+1,value.getIndexOf("</",1)-1)
#无法处理中文TAG,所以将 TAGNAME 与 VALUE 剥离出来
IF tagname = "型别名称" THEN #需求项目分析 (parser)
IF value <> "汽柴油零售" THEN
LET child = child.getNextSibling() #此处卷回WHILE,先取下一个,避免重工
CONTINUE FOR
END IF
END IF
DISPLAY tagname,":" ,value.trim() #呈现需求项目
END IF
LET child = child.getNextSibling() #取用下一个符合的
END WHILE
END FOR
END IF
END MAIN
这边有一个状况需要特别说明
**Genero在现行版本无法处理非英语文字的 TAG,要转为 STRING **
**Genero在现行版本无法处理非英语文字的 TAG,要转为 STRING **
这也是在上方案例中,『LET value = child.toString()』主要的用意。转 TAG 为STRING来进行处理,
拨离 TAG 符号,判断是否合规
分类:使用前,在程序最前端需 IMPORT xml
功能:处理任何类型的XML文档操作
Method List
特别注意:
分类:使用前,在程序最前端需 IMPORT xml
功能:一个可以承接 DomNode/DomDocument 查找出来节点(selectByXPath)存放的物件容器,方法很简单:有几个?是谁?
[Method List]
(https://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/c_gws_XmlDomNodeList_methods.html)
透过 XML 物件协助,就可以将取回的资料做好分析,在依据不同的需求进行处理即可。
最终程序运行结果
型别名称:汽柴油零售
产品名称:98无铅汽油
参考牌价:31.6
型别名称:汽柴油零售
产品名称:95无铅汽油
参考牌价:29.6
型别名称:汽柴油零售
产品名称:92无铅汽油
参考牌价:28.1
型别名称:汽柴油零售
产品名称:酒精汽油
参考牌价:29.6
FGL对於外部 WEB 资料的处理,从 1.00版的一片荒漠,到2.00版的支援SOAP,3.00版支援XML/JSON後,终於在 3.20版逐渐的补满补齐。後续的 Genero平台,将不再自外於网际网路,而可以取之於网路用之於网路。我们在後续的篇章中介绍『创造 FGL的微服务』
<<: [CSS] Flex/Grid Layout Modules, part 11
先让子弹打到敌机,可以让敌机受伤.毁坏,那首先给敌机一个受伤的动画,这次就用Animation创造一...
建构子 建构子(constructor)是一种初始化类别物件的成员函式,每一种类别都有一个建构子,当...
在开始前,我们必须的事前准备 要打包的程序 程序了话,我们就先准备一个.net core 的Hell...
再来说说我大学到转职前的经历好了。 大学时期,大一大二时其实不算个认真的大学生,就是个标准出社会人士...
Day11 延续上一回,我们尝试了 Function Composition 的技巧, 这次来试试看...