`
dcaoyuan
  • 浏览: 307353 次
社区版块
存档分类
最新评论

A Simple POET State Machine Accepting SAX Events to Build Plain Old Erlang Term

阅读更多

Per previous blogs:

I wrote a simple xml state machine that receives SAX events to build xmerl compitable XML tree.

This time, it's a simple POET (Plain Old Erlang Term) state machine, which receives SAX events to build the data in form of List and Tuple.

%%% A state machine which receives sax events and builds a Plain Old Erlang Term


-module(poet_sm).

-export([state/2]).

-export([test/0
        ]).

-record(poetsmState, {
    qname = undefined,
    attributes = [],
    content = [],
    parents = []
}).


receive_events(Events) -> receive_events(Events, undefined).

receive_events([], _States) -> {ok, [], []};
receive_events([Event|T], States) ->
    case state(Event, States) of 
        {ok, TopObject} -> 
            {ok, TopObject, T};
        {error, Reason} -> 
            {error, Reason};
        States1 -> 
            receive_events(T, States1)    
    end.

state({startDocument}, _StateStack) ->
    State = #poetsmState{},
    [State];
state({endDocument}, StateStack) ->
    %io:fwrite(user, "endDocument, states: ~p~n", [StateStack]),
    case StateStack of
        {ok, TopObject} -> {ok, TopObject};
        _ -> {error, io:fwrite(
                    user, 
                    "Bad object match, StateStack is: ~n~p~n", 
                    [StateStack])}
    end;
state({startElement, _Uri, _LocalName, QName, Attrs}, StateStack) ->
    %io:fwrite(user, "startElement~n", []),
    %% pop current State
    [State|_StatesPrev] = StateStack,
    #poetsmState{parents=Parents} = State,
    {_Pos, Attributes1} = lists:foldl(
        fun ({Key, Value}, {Pos, AccAttrs}) ->
                Pos1 = Pos + 1,
                Attr = {atom_to_list(Key), to_poet_value(Value)}, 
                %parents = [{LocalName, Pos1}|Parents]},
                {Pos1, [Attr|AccAttrs]}
        end, {0, []}, Attrs),
    Parents1 = [{QName, 0}|Parents],
    %% push new state of Attributes, Content and Parents to StateStack
    NewState = #poetsmState{qname = QName,
                            attributes = Attributes1,
                            content = [],
                            parents = Parents1},
    [NewState|StateStack];
state({endElement, _Uri, _LocalName, QName}, StateStack) ->
    %% pop current State
    [State|StatesPrev] = StateStack,
    #poetsmState{qname=ElemName,
                 attributes=Attributes,
                 content=Content,
                 parents=Parents} = State,
    %io:fwrite(user, "Element end with Name: ~p~n", [Name]),
    if  QName == undefined -> %% don't care 
            undefined; 
        QName /= ElemName -> 
            throw(lists:flatten(io_lib:format(
                "Element name match error: ~p should be ~p~n", 
                [QName, ElemName])));
        true -> undefined
    end,
    %% composite a new object
    [_|_ParentsPrev] = Parents,
    Object = 
        if  Attributes == [] ->
                {QName, lists:reverse(Content)};
            true ->
                {QName, lists:reverse(Attributes), lists:reverse(Content)} 
                %parents = ParentsPrev
        end,
    %io:fwrite(user, "object: ~p~n", [Object]),
    %% put Object to parent's content and return new state stack
    case StatesPrev of
        [_ParentState|[]] -> %% reached the top now, return final result
            {ok, Object};
        [ParentState|Other] ->
            #poetsmState{content=ParentContent} = ParentState,
            ParentContent1 = [Object|ParentContent],
            %% update parent state and backward to it:
            ParentState1 = ParentState#poetsmState{content = ParentContent1},
            %io:fwrite(user, "endElement, state: ~p~n", [State1]),
            [ParentState1|Other]
        end;
state({characters, Characters}, StateStack) ->
    %% pop current State
    [State|StatesPrev] = StateStack,
    #poetsmState{qname=_,
                 content=Content,
                 parents=Parents} = State,
    [{Parent, Pos}|ParentsPrev] = Parents,
    Pos1 = Pos + 1,
    Value = to_poet_value(Characters), %parents = [{Parent, Pos1}|ParentsPrev]},
    Content1 = [Value|Content],
    Parents1 = [{Parent, Pos1}|ParentsPrev],
    UpdatedState = State#poetsmState{content = Content1,
                                     parents = Parents1},
    [UpdatedState|StatesPrev].

to_poet_value(Name) when is_atom(Name) ->
    to_poet_value(atom_to_list(Name));
to_poet_value(Chars) when is_list(Chars) ->
    %% it's string, should convert to binary, since list in poet means array 
    list_to_binary(Chars); 
to_poet_value(Value) ->
    Value.

test() ->
    Events = [
        {startDocument},
        {startElement, "", feed, feed, [{link, "http://lightpole.net"}, {author, "Caoyuan"}]},
        {characters, "feed text"},
        {startElement, "", entry, entry, [{tag, "Erlang, Function"}]},
        {characters, "Entry1's text"},
        {endElement, "", entry, entry},
        {startElement, "", entry, entry, []},
        {characters, "Entry2's text"},
        {endElement, "", entry, entry},
        {endElement, "", feed, feed},
        {endDocument}
    ],

    %% Streaming:
    {ok, Poet1, _Rest} = receive_events(Events),
    io:fwrite(user, "Streaming Result: ~n~p~n", [Poet1]),

    {feed,[{"link",<<"http://lightpole.net">>},{"author",<<"Caoyuan">>}],
          [<<"feed text">>,
           {entry,[{"tag",<<"Erlang, Function">>}],[<<"Entry1's text">>]},
           {entry,[<<"Entry2's text">>]}]} = Poet1.

The result will be something like:

{feed,[{"link",<<"http://lightpole.net">>},{"author",<<"Caoyuan">>}],
      [<<"feed text">>,
       {entry,[{"tag",<<"Erlang, Function">>}],[<<"Entry1's text">>]},
       {entry,[<<"Entry2's text">>]}]}

The previous iCal and JSON examples can be parsed to POET by modifing the front-end parser a bit.

分享到:
评论

相关推荐

    Android代码-javapoet

    the need to write boilerplate while also keeping a single source of truth for the metadata. Example Here's a (boring) HelloWorld class: package com.example.helloworld; public final class HelloWorld {...

    Android代码生成技术JavaPoet的使用

    1. 引入依赖:首先,需要在项目的build.gradle文件中引入JavaPoet的依赖,如: ```gradle dependencies { implementation 'com.squareup:javapoet:1.13.0' } ``` 2. 创建类:接下来,我们可以使用JavaPoet API来...

    Android代码-android-studio-poet

    A tool to generate a real life Java and Kotlin Android project to analyze and improve build times. Create a real life complexity Android project that mimics your own and observe the build times. If ...

    javapoet_demo.rar

    JavaPoet是一个由Square公司开发的Java库,用于在Java源代码级别进行操作,例如创建新的类、方法、字段等。这个"javapoet_demo"压缩包文件显然包含了一个示例,展示了如何利用JavaPoet和AbstractProcessor在Android...

    Android代码-Poet Assistant

    Poet Assistant is an Android app which offers a set of tools to help with writing poems: a rhyming dictionary, using the Carnegie Mellon University pronunciation dictionary. a thesaurus, using the ...

    javapoet-1.11.1-API文档-中文版.zip

    赠送jar包:javapoet-1.11.1.jar; 赠送原API文档:javapoet-1.11.1-javadoc.jar; 赠送源代码:javapoet-1.11.1-sources.jar; 赠送Maven依赖信息文件:javapoet-1.11.1.pom; 包含翻译后的API文档:javapoet-...

    Uber提出有创造力的POET:自行开发更困难环境和解决方案.docx

    标题中的“Uber提出有创造力的POET:自行开发更困难环境和解决方案”指的是Uber AI实验室提出的一种名为POET(Paired Open-Ended Trailblazer)的技术方案,它是一种开放式的方法,旨在自动创建越来越复杂的环境并...

    poet, node.js 博客引擎.zip

    poet, node.js 博客引擎 诗人 ,查找维护帮助 ! 诗人把你的代码写在博客上。 呈现 Markdown,Jade 或者任何模板化文件,将它的标记为所需的元数据,即时分页。标记和类视图。查看 jsantell.com的源代码以查看诗人的...

    javapoet-1.11.1-API文档-中英对照版.zip

    赠送jar包:javapoet-1.11.1.jar; 赠送原API文档:javapoet-1.11.1-javadoc.jar; 赠送源代码:javapoet-1.11.1-sources.jar; 赠送Maven依赖信息文件:javapoet-1.11.1.pom; 包含翻译后的API文档:javapoet-...

    开源项目-dpolansky-go-poet.zip

    【go-poet开源项目概述】 `dpolansky-go-poet`是一个开源的Go语言包,专门用于生成`.go`源代码文件。这个项目由dpolansky开发,旨在简化和自动化Go编程中的代码生成任务,使开发者能够更加高效地构建自定义的代码...

    javapoet,爪哇语.zip

    JavaPoet是一个强大的开源项目,专门设计用于在Java编程环境中生成.java源代码文件。这个API由Square公司开发,为开发者提供了简洁、优雅的方式来构建和编辑Java源代码,从而简化了元编程任务。以下是对JavaPoet及其...

    POET-pipeline-library:POET管道框架自动化代码

    The Poet Pipeline将基于容器的现代CI / CD引入了Jenkins。 完全基于容器开发人员可以打包和共享通用步骤功能 允许在不同项目和团队之间共享和标准化复杂或复制的配置 允许基于分支,作业状态或环境变量的可选行为...

    javapoet-maven-plugin:JavaPoet Maven插件

    JavaPoet Maven插件 一个简单的maven插件,可让您使用生成项目的源。 开发JavaFile Generator 要开发JavaFile生成器, 编写public static方法 仅有一个java.lang.String参数,并且 返回java.lang.Iterable&lt;com&gt; 。...

    javapoet-master代码生成器.zip

    JavaPoet是一个强大的Java代码生成库,由Square公司开发并维护。这个库允许开发者通过简单的API来构建和编写高质量的Java源代码,极大地简化了在Java项目中自动生成代码的过程。`javapoet-master`是一个包含JavaPoet...

    Virtual Poet-开源

    "Virtual Poet" 是一个开源项目,旨在提供一个有趣的方式来创作诗歌。这个程序设计成一个小型游戏,用户可以从给定的单词列表中选择词汇,并按照一定的逻辑顺序组合这些词汇,生成诗意的句子或行。这样的设计鼓励...

    【Android 组件化】路由组件 ( 注解处理器中使用 JavaPoet 生成代码 )

    【Android 组件化】路由组件 ( 注解处理器中使用 JavaPoet 生成代码 ) https://hanshuliang.blog.csdn.net/article/details/117157837 博客源码快照

    最新的linux howto 中文合集

    # RedHat CD HOWTO, by Peter von der Ah , Morten Kjeldgaard &lt;mok@imsb.au.dk&gt;. 如何从 Red Hat 发行套件,自己制作像 Red Hat 一样的 CD-ROM. Updated 2 March 2000. # SMB HOWTO, by David Wood ...

    JavaPoet+Annotation实现android动态权限申请.7z

    在这个过程中,JavaPoet和Annotation的结合可以大大简化代码编写,提高效率。本文将深入探讨如何使用JavaPoet和Annotation来实现Android动态权限申请。 首先,让我们了解JavaPoet。JavaPoet是一个由Square公司开源...

    自己实现butterknife(javapoet)项目名(Green)

    本项目“自己实现butterknife(javapoet)”旨在通过理解ButterKnife的工作原理,利用JavaPoet这个代码生成库来创建一个类似的自定义注解处理器。下面我们将深入探讨这两个关键技术和实现步骤。 首先,让我们了解...

Global site tag (gtag.js) - Google Analytics