PowerBuilder9.0 如何使用PBDOM读取XML文件,并将其显示在TreeView中

PowerBuilder9.0 如何使用PBDOM读取XML文件,并将其显示在TreeView中

OLEObject   lobj_dom
OLEObject       lole_domnodelist,lole_domcurnode                    
string as_xml,ls_nodevalue,ls_nodename
long ll_catalog,ll_activities,ll_activity
integer li_return
boolean lb_return
string ls_id, ls_author, ls_title, ls_genre, ls_price, ls_publish_date, ls_description

lobj_dom                 = CREATE OLEObject
li_return = lobj_dom.ConnectToNewObject ("Msxml2.DOMDocument.3.0")
IF      li_return <> 0 THEN
        MessageBox ("Connection Error", "Unable to connect to the OLE object.~r~n~r~nError code = '" + String(li_return) + "'", Exclamation!, OK!)
          Return
END IF

lobj_dom.Async              = FALSE
lobj_dom.ValidateonParse    = TRUE

lb_return = lobj_dom.loadxml(as_xml)

If lobj_dom.parseError.ErrorCode <> 0  then
    Messagebox('',string( lobj_dom.parseError.reason ))
    return
end if

lole_domnodelist = lobj_dom.getElementsByTagName("catalog")
lole_domcurnode = lole_domnodelist.nextNode

// Solution 1
/* 
for ll_catalog = 0 to lole_domcurnode.childNodes.Length -1
        ls_id = lole_domcurnode.childNodes(ll_catalog).getattribute("id")
        ls_author = lole_domcurnode.childNodes(ll_catalog).childNodes.Item(0).text      
        ls_title = lole_domcurnode.childNodes(ll_catalog).childNodes.Item(1).text       
        ls_genre = lole_domcurnode.childNodes(ll_catalog).childNodes.Item(2).text       
        ls_price = lole_domcurnode.childNodes(ll_catalog).childNodes.Item(3).text               
        ls_publish_date = lole_domcurnode.childNodes(ll_catalog).childNodes.Item(4).text        
        ls_description = lole_domcurnode.childNodes(ll_catalog).childNodes.Item(5).text             
        Messagebox(string(ll_catalog),ls_id + '~r~n' + ls_author + '~r~n' + ls_title + '~r~n' + ls_genre + '~r~n' + ls_price + '~r~n' + ls_publish_date + '~r~n' + ls_description)
Next
*/

// Solution 2

for ll_catalog = 0 to lole_domcurnode.childNodes.Length -1
        ls_id = lole_domcurnode.childNodes(ll_catalog).getattribute("id")   
        ll_activities = lole_domcurnode.childNodes(ll_catalog).childNodes.length - 1
        For ll_activity = 0 to ll_activities
            ls_nodename  = lole_domcurnode.childNodes(ll_catalog).childnodes.Item(ll_activity).nodeName
            ls_nodevalue = lole_domcurnode.childNodes(ll_catalog).childNodes.Item(ll_activity).text 
            Choose Case ls_nodename
                Case 'author'
                    ls_author = ls_nodevalue
                Case 'title'                    
                    ls_title = ls_nodevalue
                Case 'genre'
                    ls_genre = ls_nodevalue
                Case 'price'
                    ls_price = ls_nodevalue
                Case 'publish_date'
                    ls_publish_date = ls_nodevalue
                Case 'description'
                    ls_description = ls_nodevalue
            End Choose
        Next
        Messagebox(string(ll_catalog),ls_id + '~r~n' + ls_author + '~r~n' + ls_title + '~r~n' + ls_genre + '~r~n' + ls_price + '~r~n' + ls_publish_date + '~r~n' + ls_description)      
Next

http://blog.csdn.net/lxqluo/article/details/6109144

本文对PBDOM技术进行相关介绍,但并不涉及XML的基础知识,建议阅读者对下述相关术语有一定了解: Document(文档), DTD(文档类型定义), schema(大纲),Element(元素), attribute(属性), processing instruction(处理命令), entity(实体)。

本文主要包括以下内容:
1、为什么要使用PBDOM以及怎样创建PBDOM
2、PBDOM主要用于那些地方
3、如何使用PBDOM编程
4、PBDOM和其他XML解析(parser)技术的比较

一、什么是DOM
◆文档对象模型(Document Object Model)
1、作为一项W3C规范,XML DOM存在目的是为不同类型的应用程序提供一个标准的编程接口,它被设计可以跨平台、跨语言使用。
2、我们可以利用XML DOM创建XML文档并操纵其结构,增加、修改、删除元素。
3、程序中调用XML解析器载入XML文档到内存中。当文档被载入后,可以通过进入DOM检索和操作相关信息。
4、DOM 保存了XML文档树,文档(document)元素位于整棵树的最顶层。该元素可以有一到多个子节点来保存树的结构。

可以参阅以下网站: http://www.w3schools.com/dom/ 来了解更多的关于XML Document Object Model的内容。

二、什么时候应该使用DOM工具
◆当你需要做下列事情的时候,你应该想到XML DOM的

1、在一个或者多个XML文档之间移动元素
2、创建新的元素并且在XML文档的任意位置插入
3、操作元素并重新插入其到XML文档其他位置
4、导入内嵌数据结构

& . pb9中,数据窗口现在可以通过XML导出内嵌数据结构(nested data structures).

三、什么是PBDOM
◆PowerBuilder 文档结构模型(PowerBuilder Document Object Model)

1、PBDOM是通过PBNI扩展出来的,用于操作XML数据,并针对PowerScript作了优化
2、在程序中模型是通过DOM的抽象来表示XML数据。(A programming model to represent XML data –an abstraction of DOM)
3、底层是对Apache Xerces/C++的封装。

四、PBDOM的设计目标

1、简单易用(Be straightforward for PowerBuilder programmers)
2、可以利用PowerScript的强大语言能力(如对象、方法重载、数据等)
3、在可能的情况下,隐藏了XML底层的复杂实现(Hide the complexities of XML wherever possible)
4、原有的DOM在pb下使用不够直观(DOM is unintuitive to a PowerBuilder programmer)

五、使用PBDOM初步
◆PBDOM设置
1、添加pbdom90.pbd(%SYBASE%\Shared\PowerBuilder)到工程的pbl列表中
2、%SYBASE%\Shared\PowerBuilder应该在系统路径或者应用程序的路径中(也就是pbdom要使用此路径下的pbdom90.dll, pbxerces90.dll、xerces_2_1_0.dll文件,同样,当程序发布时候也需要)

六、PBDOM类的使用

◆如图所示,反映了PBDOM类的组成和继承关系,可以看到,几乎所有的PBDOM类都继承自PBDOM_Object(除了PBDOM_Builder和PBDOM_Exception)

1、PBDOM_Document
◆构建PBDOM举例

1.1 直接构建(XML documents can be created from scratch)
PBDOM_Document doc
PBDOM_Element rootdoc = CREATE PBDOM_Document
root = CREATE PBDOM_Element
root.SetName( "root" )
root.SetText( "this is the root" )
doc.AddContent( root )

1.2 从文件、字符串、DataStore中载入
PBDOM_Builder builder
doc = builder.BuildFromString( "bar" )
doc = builder.BuildFromFile( "c:\foo\bar.xml"
doc = builder.BuildFromDataStore( l_ds)

2、PBDOM_Element
2.1 遍历元素
PBDOM_Element root, children[], first
// Get the root element of the document
root = doc.GetRootElement()
// Get an array of all child elements
root.GetChildElements( children )
// Get only elements with a given name
root.GetChildElements( "name", children )
// Get the first element with a given name
first = root.GetChildElement( "name" )

注意:

上例中得到的元素数组是联动的!(The element array is live!) 即:
◆ 修改数组中的元素,同样会作用到父文档
◆ 返回的数组是有界的(Once the array is returned, it is now bounded)
◆ 在数组中增加新元素时,需要一个SetContent()方法调用

2.2 移动元素
// PBDOM_Document docOne,docTwo
PBDOM_Element movable

movable = CREATE PBDOM_Element
Movable.SetName( "movable" )
docOne.AddContent( movable ) // add
movable.Detach() // remove
docTwo.addContent( movable ) // add again

注意:

1、只要是从PBDOM_Object继承的对象,都可以调用Detach()方法(如Comments、ProcessingInstructions、Elements (and their content)等等)
2、PBDOM元素对象不是永久的捆绑在它的父文档上的(PBDOM elements aren't permanently tied to their parent document)

2.3 符合规格(Always well-formed)
PBDOM_Element构造器以及setter方法会检查元素是否符合规格:

   elem.SetName( "Spaces are illegal" )

AddContent()方法也会从以下几个方面进行检查:
◆ 结构---树中没有循环(Structure –no loops in any tree)
◆ 只有一个根节点元素(One and only one root element)
◆ 相容的命名空间(Consistent namespaces)

3、PBDOM_Attribute
3.1 操作元素属性
◆ 元素可以有多个属性

// Get an attribute
ls_width = table.GetAttributeValue( "width" ) // or
ls_width = table.GetAttribute ( "width" ).GetText()
// Attributes can be typed
li_border = table.GetAttribute( "width" ).GetIntValue()

// Set an attribute
table.SetAttribute( "cellspacing", "0" )
// Remove an attribute
table.RemoveAttribute( "cellspacing" )
// Remove all attributes
PBDOM_Attribute empty[]
table.SetAttributes( empty ) // the PowerScript way

4、PBDOM_Text
4.1 操作元素文本内容

cool demo

// the text is directly available –returns
// "~r~ncool demo~r~n"
ls_desc= elem.GetText()

// two convenience methods
ls_desc= elem.GetTextTrim()// returns "cool demo"
ls_desc = elem.GetTextNormalize()// returns "cool demo"

// text can be changed directly
elem.SetText( "a new description" )

5、PBDOM_Object
5.1 操作有混合内容的元素

<!–comment -->
<?convert units="metric" ?>
cool demo

PBDOM_Object content[]
desc.GetContent( content )
FOR i = 1 TO UpperBound( content )
CHOOSE content[i].GetObjectClassString()
CASE "pbdom_comment"
// ...
CASE "pbdom_processinginstruction"
// ...
END CHOOSE
NEXT

6、PBDOM_ProcessingInstruction
6.1 使用处理命令(Processing instructions)
<? xml-stylesheet type="text/xsl"href="foo.xsl" _fcksavedurl=""foo.xsl"" ?>
{------target------} {----------------data---------------}

// Get target (e.g., "xsl-stylesheet")
ls_target = pi.GetTarget()

// Get data (e.g., 'type="text/xsl"href="foo.xsl"')
ls_data = pi.GetText()

// Get individual values as attributes
String names[]
pi.GetNames( names )
FOR i = 1 TO UpperBound( names )
MessageBox( names[i], pi.GetValue( names[i] )
NEXT

7、PBDOM and 命名空间(Namespaces)


......
/xsl:template
/xsl:stylesheet

String ls_element
PBDOM_Element template

// get element name and namespace –return "xsl:template"
template = root.GetChildElement( "template" )
ls_element= template.GetNamespacePrefix() +":"+ template.Getname()

// get element by name and namespace
template = root.GetChildElement( "template", "xsl", "http://www.w3.org/1999/XSL/Transform")

七、PBDOM vs. the Competition
◆Apache Xerces/COM
Xerces 是现在PBDOM底层使用的XML解析器,但对PowerBuiler用户来说使用不直观。(Xerces is the [current] underlying XML parser for PBDOM, but is less intuitive)

◆MSXML
.无法在UNIX等操作系统上使用(No deployment to UNIX possible)
.同样对PowerBuiler用户来说使用不够直观(Less Intuitive)
.COM collections vs. PB arrays (pb用户当然会优先选择使用数组来处理数据)

◆Others
Expat–a C DLL (使用时需要声明外部函数…使用不够广泛)

使用SetLibrary动态组装系统
当所开发的系统变得越来越庞大时,或基于商业利益或用户操作习惯考虑需要分割成多个系统时,动态组装系统就成为必要的功能了。如果使用PB作为前台开发工具,使用SetLibrary函数可以很方便地实现系统的组装。

   通常的做法是在应用对象(或类似功能的对象)的Open事件读取配置文件的动态库列表数据(如LibraryList段),将动态库文件转换为含有完整路径的文件,使用GetLibraryList函数获取原有的库文件列表,新旧库文件列表组合(使用逗号分隔),最后调用SetLibrary函数更改库文件列表。

   由于SetLibrary函数在PB开发环境下无效,一般应判断程序是否运行在编译环境,可使用Handle(GetApplication())是否大于0来做出判断。

   与SetLibrary函数相似功能的函数还有AddToLibraryList,也可以通过它动态加载库文件。

exit、continue在pb中的应用

1、continue语句

该语句用在循环中,可以直接使用,没有任何参数。PowerBuilder在执行循环时如果遇到continue语句,就直接跳转到next或loop语句处,忽略当前循环中continute和next(或loop)之间的语句,然后继续执行循环。例如,下面的语句当li_b > 3时就不会显示提示窗口:

integer li_a = 1, li_b = 1

DO WHILE li_a < 100

li_a = li_a + 1

li_b = li_b + 1

     If li_b > 3 THEN CONTINUE

               MessageBox("Hi", "li_b is " + String(li_b) )

LOOP

再如,下面的continue语句用在for循环中,当li_count>15时不再增加li_b:

integer li_a = 0, li_b = 0, li_count

FOR li_count = 1 TO 100

               li_a = li_a + 1

     IF li_count > 15 THEN CONTINUE

               li_b = li_b + 1

NEXT

//上面的语句执行完毕后,li_a = 100 li_b = 15

2、exit语句

该语句用在循环中,可以结束循环,执行紧跟在循环之外的语句。该语句也是直接使用,没有任何参数。例如,下面的例子检查数组lai_Nbr中是否有等于0的,如果有就立即停止循环。

int lai_Nbr[10],li_count

For li_count = 1 To 10

     lai_Nbr[li_count] = rand(10) - 1

Next

li_count = 1

DO WHILE li_count < 11

IF lai_Nbr[li_count] = 0 THEN EXIT

     li_count = li_count + 1

LOOP

MessageBox("提示", "现在的li_count值是" + String(li_count) )

在MSSQL的Cursor中LOCAL和GLOBAL关键字
LOCAL指定该游标的作用域对在其中创建它的批处理、存储过程或触发器是局部的。该游标名称仅在这个作用域内有效。在批处理、存储过程、触发器或存储过程 OUTPUT 参数中,该游标可由局部游标变量引用。OUTPUT 参数用于将局部游标传递回调用批处理、存储过程或触发器,它们可在存储过程终止后给游标变量指派参数使其引用游标。除非 OUTPUT 参数将游标传递回来,否则游标将在批处理、存储过程或触发器终止时隐性释放。如果 OUTPUT 参数将游标传递回来,游标在最后引用它的变量释放或离开作用域时释放。

GLOBAL指定该游标的作用域对连接是全局的。在由连接执行的任何存储过程或批处理中,都可以引用该游标名称。该游标仅在脱接时隐性释放。

说明 如果 GLOBAL 和 LOCAL 参数都未指定,则默认值由 default to local cursor 数据库选项的设置控制。默认是GLOBAL,如果在建PROCEDURE中用到Cursor并出现递归则必须指定为LOCAL。

ALTER procedure UpdateFormula
@ID int
AS

Declare @NewID int
Declare @MaxLevel int
Declare @ItemName VarChar(50)
Declare @FormulaStr VarChar(2000)

Select @ItemName=B.ItemName,@FormulaStr=A.FormulaStr
From HR_Formulas A Left Join HR_Items B On A.ItemID=B.ID Where A.ID=@ID

Select @MaxLevel=Max(FormulaLevel)
From HR_Formulas A Left Join HR_Items B On A.ItemID=B.ID Where CharIndex(B.ItemName,@FormulaStr)>0
IF @MaxLevel IS NULL Set @MaxLevel=0
Update HR_Formulas Set FormulaLevel=@MaxLevel+1 Where ID=@ID

Declare IDS_Cursor Cursor local scroll For
Select ID From HR_Formulas Where CharIndex(@ItemName,FormulaStr)>0
Open IDS_Cursor
Fetch Next From IDS_Cursor Into @NewID
While @@Fetch_Status=0
Begin
Exec UpdateFormula @NewID
Fetch Next From IDS_Cursor Into @NewID
End
Close IDS_Cursor
Deallocate IDS_Cursor

SetRedraw () 是 PB 中几乎所有的可是控件都具备的函数。SetRedraw 的用 意的关闭或开启控件的重画功能。如果一个控件或窗口被别的 A 挡住了,然后 A 此时有移开了或关闭了。那么 Window 将会通知这个控件或者窗口要求他们重 画一遍自己,这就是重画的意思。 当 DataWindow 检索大量数据时 SetRedraw 函数就大有用途了。DataWindo w 每检索出一条数据便会重画一边 DataWindow 。因此如果有大量的数据需要检 索的话,那么 DataWindow 将会频繁闪烁。同时也消耗了大量的 CPU 资源。因此 ,我们可以在检索数据之前调用 SetRedraw ( False ) 关闭重画功能,在数据检索完后在开启重画功能,即 SetRedraw ( Tru e )。这样便消去了闪烁现象,最关键是大大地提高了检索速度.

dw_1.ScrollToRow(1) //第一条记录

dw_1.ScrollPriorRow() //前一记录

dw_1.ScrollNextRow() //下一记录

dw_1.ScrollToRow(dw_1.RowCount()) //最后一条记录

7、【上一条】按钮的Clicked事件

dw_1.scrollpriorrow()

dw_1.selectrow(0,false) //不选择任何行,取消所有已经选择的行:

dw_1.selectrow(dw_1.getrow(),true) //将当前行加亮显示

8、【下一条】按钮的Clicked事件

dw_1.scrollnextrow()

dw_1.selectrow(0,false)

dw_1.selectrow(dw_1.getrow(),true)

9、【升序】按钮的Clicked事件

dw_1.settransobject(sqlca)

dw_1.setsort(“职工号 A”)

dw_1.sort()

dw_1.retrieve()

10、【降序】按钮的Clicked事件

dw_1.settransobject(sqlca)

dw_1.setsort(“职工号 B”)

dw_1.sort()

dw_1.retrieve()

参考链接如下:
http://blog.163.com/zuoxuesheng@126/blog/static/15732173201010414742681/