rexml 中增加CDATA

最近想用ruby写个能生成ibatis sqlmap的xml文件,以前一直没注意,找了下才发现自带的包中就有,那就是rexml,在生成普通的文本内容时没什么问题,今天突然准备把有些sql语句放在
<![CDATA[ ]]>里面,结果就是不能成功。不管怎么放,“〈〉”这两个尖括号都会被转义,在网上找了下也没发现什么答案,小众语言就是这样,找资料难。
好不容易找到了一个关于cdata.rb的内容,虽然没怎么说清楚,但至少提供了思路,于是自己就看了下ruby lib中的cdata.rb的源码,有一个write可以用,用法如下:


c = CData.new( " Some text " )
c.write( $stdout ) #-> <![CDATA[ Some text ]]>


这个方法应该可行,它也继承自Text,也就是用于Text的地方也可用于CData,但是这个方法却写着deprecated标记,注释上说去看 rexml/formatters,于是自己找到该目录,下面有三个文件:default.rb pretty.rb transtive.rb,那么自己用的又是那个formatter呢? 由于输出的代码是这句:

doc.write(xmlFile,4)

于是自己找到document的write方法:


def write( output=$stdout, indent=-1, transitive=false, ie_hack=false )
if xml_decl.encoding != "UTF-8" && !output.kind_of?(Output)
output = Output.new( output, xml_decl.encoding )
end
formatter = if indent > -1
if transitive
require "rexml/formatters/transitive"
REXML::Formatters::Transitive.new( indent, ie_hack )
else
REXML::Formatters::Pretty.new( indent, ie_hack )
end
else
REXML::Formatters::Default.new( ie_hack )
end
formatter.write( self, output )
end

因为indent为4,所以应该采用的是Pretty这个formatter,毫不犹豫的打开pretty.rb这个文件,看了几分钟,除了一个名叫write_cdata的方法有点像以外,没发现什么特别的:

def write_cdata( node, output)
output << ' ' * @level
super
end

但这个方法也没什么特别的,非常的普通,怎么看都不会输出"<![CDATA ]]>"这些东西,于是只能看看其父类有没有什么特别的了。因为pretty的父类是default,于是找到default的write_cdata方法:


def write_cdata( node, output )
output << CData::START
output << node.to_s
output << CData::STOP
end

答案找到了,问题似乎解决了,于是自己写了个简单的语句测试了下:

t = REXML::Formatters::Default.new
puts t.write_cdata("fff",$stdout);

但控制台提示write_cdata方法是pretected的,外部不能使用,那怎么办呢?最后看了半天才找到答案,自己忽略了document中write的最后一句话:

formatter.write( self, output )


这句话比较关键,于是找到Default的write方法:

def write( node, output )
case node

when Document
if node.xml_decl.encoding != "UTF-8" && !output.kind_of?(Output)
output = Output.new( output, node.xml_decl.encoding )
end
write_document( node, output )

when Element
write_element( node, output )

when Declaration, ElementDecl, NotationDecl, ExternalEntity, Entity,
Attribute, AttlistDecl
node.write( output,-1 )

when Instruction
write_instruction( node, output )

when DocType, XMLDecl
node.write( output )

when Comment
write_comment( node, output )

when CData
write_cdata( node, output )

when Text
write_text( node, output )

else
raise Exception.new("XML FORMATTING ERROR")

end
end

终于找到答案了,内容的格式是由node的类型决定的,也就是说,只要创建一个CData对象,将此对象赋给Text即可,document知道怎么输出:

_cdata = CData.new "select * from \n(select rownum as r,s.* from
(select #{_field_as_attr*','} from #{@@table}"
_select_all.text=_cdata

这样输出的xml就会包含在"<![CDATA[]]>"内。而且由上面default.write方法可以看出,如果要加入其它结点类型,比如Comment、DocType、XMLDecl等类型时,只需要创建相应的对象,然后添加进相应的对象即可,相应的格式自然就可以生成了。

这个问题几乎花了自己一上午的时间,虽然ruby以前也有学过,但一直没怎么用,几乎都忘光了,昨几天才书店偶然看见了ruby之父松本行弘(这个名字很不好记)的一本书叫 松本行弘的程序世界,发行这本书写得挺不错的,上面说到可以用ruby来写些工具类用用,于是再次拿起原来的那本ruby programming看了看,两三天的时间基本上就把生成ibatis的sqlmap文件,基本的dao、service、domain之类的东西就写成了,效率确实远高于用java来写,然后在网上把那本<松本行弘的程序世界>买了下来(网上买七五折不加邮费,确实比书店的便宜多了,鄙人在新华书店买了不少书,从来没打折)。ruby确实是一门很有意思的语言,在开发过程中总会有些地方让自己惊讶与欣喜,这是使用其它任何语言都未有过的,特别是java,用java开发程序这么久,基本上都是厌倦。

10.19:另外,如果想在各个element这间加上空白换行符,如:

<select id="getUserTypeNextId" resultClass="long">
</select>

<insert id="addUserType" parameterClass="userType">
</insert>

<update id="updateUserType" prameterClass="string">
</update>

<delete id="deleteUserType" parameterClass="string">
</delete>

这个问题本人看了文档,主要看了Element与 Document这两个类,均没有什么收获,于是再去看了下Formatters模块的Pretty,也没发现什么参数可用,看来只能改源代码了。直接修改Pretty的write_element方法:

def write_element(node, output)
.........
end
output << ">"
output << "\n"
end

也就是在该元素最后一行加上换行符就行了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值