就是像CSDN这样,不要打开XML显示的是它的一层一层的数据,而要是像网页一样的效果,怎么做?是不是要加个XSLT?但是我刚接触它,不太熟悉,哪位可以帮帮我?谢谢!

解决方案 »

  1.   

    我这里有代码,要吗
    方法一:
    unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs,MSXML2_TLB, xmldom, XMLIntf, ExtCtrls, DBCtrls, StdCtrls, Grids,
      DBGrids, DB, msxmldom, XMLDoc, DBTables, DBClient,ComObj, ComCtrls;
    type
      TForm1 = class(TForm)
        Button1: TButton;
        Table1: TTable;
        XMLDocument1: TXMLDocument;
        DataSource1: TDataSource;
        Label1: TLabel;
        Button3: TButton;
        DBNavigator2: TDBNavigator;
        PageControl1: TPageControl;
        TabSheet1: TTabSheet;
        TabSheet2: TTabSheet;
        Memo1: TMemo;
        DBGrid1: TDBGrid;
        DateTimePicker1: TDateTimePicker;
        ComboBox1: TComboBox;
        Label2: TLabel;
        procedure Button3Click(Sender: TObject);
        procedure Button1Click(Sender: TObject);
        procedure ComboBox1Change(Sender: TObject);
       private
        { Private declarations }
        doc :IXMLDomDocument;
        root,child,child1 :IXMLDOMElement;
        function makeXml(table:TTable):Integer;
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button3Click(Sender: TObject);
    begin
      Form1.Close
    end;//添加makeXml函数单元。它将通过读取DBDEMOS中contry表中的数据生成一个XML文件。
    function TForm1.makeXml(table:TTable):Integer;
    var
        i   : Integer;
        xml,temp : String;
      begin
        try
          table.close;
          table.open;
          xml  := table.TableName;
          doc  := CreateOleObject('Microsoft.XMLDOM') as IXMLDomDocument;
          //Set the root name of the xml file as that of the table name. 
          //In this case "country" 
          root := doc.createElement(xml);
          doc.appendchild(root);
          //This while loop will go through the entaire table to generate the xml file 
          while not table.eof do 
          begin 
            //adds the first level children , Records 
            child:= doc.createElement('Records');
            root.appendchild(child);
            for i:=0 to table.FieldCount-1 do 
            begin 
              //adds second level children 
              child1:=doc.createElement(table.Fields[i].FieldName); 
              child.appendchild(child1); 
              //Check field types 
              case TFieldType(Ord(table.Fields[i].DataType)) of 
              ftString: 
              begin 
                if Table.Fields[i].AsString ='' then 
                     temp :='null'  //Put a default string 
                   else 
                     temp := table.Fields[i].AsString; 
              end; 
      
              ftInteger, ftWord, ftSmallint: 
              begin 
                  if Table.Fields[i].AsInteger > 0 then 
                     temp := IntToStr(table.Fields[i].AsInteger) 
                   else 
                     temp := '0'; 
              end; 
              ftFloat, ftCurrency, ftBCD: 
              begin 
                  if table.Fields[i].AsFloat > 0 then 
                    temp := FloatToStr(table.Fields[i].AsFloat) 
                  else 
                     temp := '0'; 
              end; 
              ftBoolean: 
              begin 
                  if table.Fields[i].Value then 
                    temp:= 'True' 
                  else 
                    temp:= 'False'; 
              end; 
              ftDate: 
              begin 
                  if (not table.Fields[i].IsNull) or 
                     (Length(Trim(table.Fields[i].AsString)) > 0) then 
                    temp := FormatDateTime('MM/DD/YYYY', 
                                   table.Fields[i].AsDateTime) 
                  else 
                    temp:= '01/01/2000'; //put a valid default date 
              end; 
              ftDateTime: 
              begin 
                  if (not table.Fields[i].IsNull) or 
                     (Length(Trim(table.Fields[i].AsString)) > 0) then 
                    temp := FormatDateTime('MM/DD/YYYY hh:nn:ss',
                                   Table.Fields[i].AsDateTime)
                  else 
                    temp := '01/01/2000 00:00:00'; //Put a valid default date and time 
              end; 
              ftTime: 
              begin 
                  if (not table.Fields[i].IsNull) or 
                     (Length(Trim(table.Fields[i].AsString)) > 0) then 
                     temp := FormatDateTime('hh:nn:ss', 
                                 table.Fields[i].AsDateTime) 
                  else 
                     temp := '00:00:00'; //Put a valid default time 
              end; 
            end; 
             //
             child1.appendChild(doc.createTextNode(temp));
            end; 
          table.Next; 
          end;
          doc.save(xml+'.xml');
          memo1.lines.Append(doc.xml);
          Result:=1; 
        except 
          on e:Exception do 
            Result:=-1; 
        end; 
      end; //在Button1的onclick事件中调用上面的函数
    procedure TForm1.Button1Click(Sender: TObject);
    begin
       showmessage('开始生成!');
        if makeXml(table1)=1 then
          showmessage('XML Generated')
        else
          showmessage('Error while generating XML File');
    end;
    procedure TForm1.ComboBox1Change(Sender: TObject);
    begin
       showmessage('改变表名');
    end;end.
      

  2.   


    方法二: 
    解析XML
        XML可以以一种通用的方式来储存数据,数据可以使用DOM解析器解析。本文就将讨论如何使用微软提供的XML解析器来解析简单的XML文件。      DOM是文档对象模型的缩写(Document Object Model)。我们可以使用DOM来查找HTML或XML文档中的元素。本文将不会详细解释DOM和XML,想了解这方面更多的信息请查阅其他资料。 本文中将要用到的微软的XML解析器是随Internet Explorer缺省安装的,因此在绝大多数的Windows中都可以获得支持。建立一个简单的XML解析程序    同其他的COM应用程序一样,要想使用XML解析器,我们需要引入XML控件的类型库。注意这里要先确保系统中安装了Internet Explorer 5.0。选择菜单命令Project | Import Type Library ,选择引入Microsoft XML, version 2.0(如图1.61)。点OK按钮,就会在ActiveX控件面板上安装XML解析控件。     然后创建一个新的应用程序,在窗体上放置Tbutton、TMemo和TListBox控件。再放上一个刚才安装的XML解析控件TDomDocument。为按钮创建一个OnClick事件,输入下面代码:    procedure TForm1.Button2Click(Sender: TObject);     var       Len,i: Integer;      ElemList: IXMLDOMNodeList;    begin      DOMDocument1.load('c:\temp\sam1.xml');      Len := DOMDocument1.documentElement.childNodes.Get_length;      for i := 0 to Len - 1 do begin        Memo1.Lines.Add('节点名称  := ' + OMDocument1.documentElement.Get_ nodeName);        Memo1.Lines.Add('');        Memo1.Lines.Add(DOMDocument1.documentElement.childNodes.item[i].Text);      end;      ElemList := DOMDocument1.documentElement.getElementsByTagName('CD');      for i := 0 to ElemList.length -1 do        ListBox1.ITems.Add(ElemList.item[i].xml);    end;    上面的代码使用XML解析器来遍历一个XML文件,然后显示它的内容。首先,在第一行代码中,我们使用DOMDocument控件加载了一个XML文件,下面就是XML文件的内容:    <HTML>      <HEAD>        <TITLE>Sample XML File</TITLE>      </HEAD>      <BODY>        <P>Right under this line I insert an XML data island.</P>         <XML ID="CDXML">        <CDS>          <CD>Two Against Nature</CD>          <CD>Giant Steps</CD>          <CD>Round About Midnight</CD>          <CD>Imaginary Day</CD>        </CDS>        </XML>      </BODY>    </HTML>      代码的第二部分是查找在文档中最顶层有多少个节点。文档的节点是按树状结构组织的,比如<CD>节点就在<CDS>下面一级。下面这条语句就是为获得节点数的:    Len := DOMDocument1.documentElement.childNodes.Get_length;    接下来就是遍历这些节点然后察看它们的内容,代码如下:     var       Len,i: Integer;      ElemList: IXMLDOMNodeList;    Begin      //省略…      DOMDocument1.load('c:\temp\sam1.xml');      Len := DOMDocument1.documentElement.childNodes.Get_length;      for i := 0 to Len - 1 do begin        Memo1.Lines.Add('节点名称  := ' + OMDocument1.documentElement.Get_ nodeName);        Memo1.Lines.Add('');        Memo1.Lines.Add(DOMDocument1.documentElement.childNodes.item[i].Text);      end;      //省略…    end;    代码忽略了顶层的HTML标记,然后把XML内容分成两部分,第一个节点包括HEAD元素,第二个节点包括 BODY元素。另外要想更深入挖掘文档内容,可以使用ChildNodes属性来察看子节点的内容,这在后面将会谈到,这里我们还想知道特殊节点的信息,比如想知道所有关于CD的销售信息。要想获得这方面的信息,可以使用GetElementsByTagName 方法,代码如下:    var       Len,i: Integer;      ElemList: IXMLDOMNodeList;    begin      //省略…      ElemList := DOMDocument1.documentElement.getElementsByTagName('CD');      for i := 0 to ElemList.length -1 do        ListBox1.ITems.Add(ElemList.item[i].xml);    end;    正如我们看到的,可以直接获得文件中特定的标记,这里简单地输出了所有<CD>标记列表:     <CD>Two Against Nature</CD>    <CD>Giant Steps</CD>    <CD>Round About Midnight</CD>    <CD>Imaginary Day</CD>    从上面我们可以看到解析XML是非常简单的,整个程序运行结果如图1.62所示。
      

  3.   


    深入XML解析    下面演示如何解析更复杂的XML文件,并用TTreeView控件来显示XML文档的树状结构。要想知道XML的标准定义,可参见http://www.w3.org/XML/。    下面的例子中将使用一个封装了XML解析器的对象,它可以简化对XML文件的解析。在具体解释这个对象前,先来看看我们将要实现的例子,这个例子允许选择想要解析的XML文件,然后查找主要的节点,并显示在页面右侧的树视图中(如图1.63),另外这里用来演示XML解析的文件是一个MIDAS生成的XML数据包文件。    如果打开文件的METADATA节点,将会看到数据字段和参数节点,如图1.64所示。       
        由图可见字段名为KeyNum、KeyFields等,而其中的数据分别为01-0001-W1-B、1、BLWORD 等。同时还可以知道Borland是如何把数据保存在XML文件的ROW元素中的。下面是Borland在XML文件中保存原始数据的方式:     <ROW KeyNum="02-0004-W1-B"KeyFields="14"FileName="BLWORD"Chap-ter="2"Num="4"/>    他们没有用下面这种方式保存:    <ROW>      <KEYNUM>02-0004-W1-B</KEYNUM>      <KEYFIELDS>14</KEYFIELDS>      <FILENAME>BLWORD</FILENAME>      <CHAPTER>Chapter</CHAPTER>      <NUM>4</NUM>    </ROW>    可能的原因是为了节省空间吧,后面我们还将演示如何解析第二种结构的XML文档。要注意的是对于 Borland MIDAS技术来说,它是把每个数据记录的内容都按Row元素的属性进行保存,从树视图中看好像KeyNum、KeyFields、FileName、Chapter 和Num字段是Row元素的元素节点,这其实是一种误解。缺省条件下,封装的对象不会把属性显示为如图1.65的独立的子节点形式,而是显示为如图1.66的形式。理解代码    下面该是讨论前面提到的封装对象问题的时候了,这个对象名为TCSCXMLParserMS。它的核心方法是WriteIt。这种方法使用微软的解析引擎来解析XML文件,每当它查找到文件中的节点后,它将会激发事件,并在事件中返回节点名和节点在文档节点树中的深度。  
        使用TCSCXMLParseMS对象时,传递一个IXMLDomNode接口给WriteIt方法,WriteIt方法然后就会查找所有的子节点,每发现一个节点就会激发相应的事件,代码如下:       if OpenDialog1.Execute then begin        Memo1.Clear;        TreeView1.Items.Clear;        DomDocument1.Load(OpenDialog1.FileName);        AddToTree(Self, 0, 'Doc');        Parse := TCSCXMLParseMS.Create;        // 切环 BreakoutAttributes属性        Parse.BreakoutAttributes := True;        Parse.OnElementNode := AddToTree;        Parse.OnAnyNode := AddToMemo;        Parse.WriteIt(DomDocument1.DocumentElement, 0);        parse.Free;      end;    WriteIt 方法的基本结构非常简单,它处理每一种可能的节点类型:     procedure TCSCXMLParseMS.WriteIt(toWrite: IXMLDomNode; Level: Integer);    begin      case (toWrite.NodeType) of        NODE_TEXT:         NODE_PROCESSING_INSTRUCTION:          NODE_DOCUMENT:         NODE_ELEMENT:        NODE_ENTITY_REFERENCE:        NODE_CDATA_SECTION:        NODE_COMMENT:         else      end;    end;    上面的节点类型定义常数声明在MSXML_TLB.pas文件中,很多节点类型包含子节点,下面的代码演示了如何递归子节点:    NODE_ENTITY_REFERENCE:    begin      // 省略…       child := toWrite.FirstChild;      while child <> nil do      begin        WriteIt(child, Level);        child := child.NextSibling;      end;    end;    其他节点类型的处理同NODE_ENTITY_REFERENCE类型非常类似。 接下来要讨论的则是对象的事件机制。理解事件模型     TCSCXMLParseMS 对象有两个事件,一个返回描述节点的字符串,另一个返回节点元素,节点属性和文本节点的相关信息。后一个事件还会返回一个整数表明节点在节点树中的深度。下面是两个事件的定义:    TAnyNodeEvent = procedure(Sender: TObject; Value: string) of object;    TElementNodeEvent = procedure(Sender: TObject; Level: Integer; Value: string) of object;    对于前面运行的示意图来说,TAnyNodeEvents 事件返回的信息显示在窗体的左侧,而TElementNodeEvents 事件返回的信息显示在右侧的TTreeView 控件中。    下面是TCSCXMLParser对象的声明,它显示了事件是如何集成到对象中的:       TCSCXMLParseMS = class      private        FBreakoutAttributes: Boolean;        FElementNodeEvent: TElementNodeEvent;        FAnyNodeEvent: TAnyNodeEvent;        function OutputContent(const toWrite: String; doEscapes: Boolean): string;        procedure WriteIt(toWrite: IXMLDOMNode; Level: Integer);        function GetElementNodeEvent: TElementNodeEvent;        procedure SetElementNodeEvent(const Value: TElementNodeEvent);        procedure SetAnyNodeEvent(const Value: TAnyNodeEvent);      public        procedure WriteDom(toWrite: IXMLDOMNode);        property OnAnyNode: TAnyNodeEvent          read FAnyNodeEvent          write SetAnyNodeEvent;        property BreakoutAttributes: boolean          read FBreakoutAttributes          write FBreakoutAttributes;        property OnElementNode: TElementNodeEvent          read GetElementNodeEvent          write SetElementNodeEvent;      end;    对象包含类型为TElementNodeEvent和TAnyNodeEvent的属性OnAnyNode和OnElementNode,下面是WriteIt 方法中调用事件的代码:       if Assigned(FElementNodeEvent) then        FElementNodeEvent(Self, Level, DomNode.NodeValue);    代码首先使用Assign 方法判断FElementNodeEvent 事件指针是否为nil。如果是的话,表明没有任何方法被赋值给指针,因此不会激发事件,否则事件的处理方法就会被调用,并返回相关的数据。     查找文本节点部分的代码可以很好地用来理解事件机制的工作方式:       NODE_TEXT: begin        if Assigned(FAnyNodeEvent) then          FAnyNodeEvent(Self, 'text: ' + toWrite.nodeValue);        if Assigned(FElementNodeEvent) then          FElementNodeEvent(Self, Level - AValue, toWrite.NodeValue);      end;    上面的部分代码相对简单,主要是因为文本节点没有子节点,无需递归调用,只要返回相关的文本就可以了。 处理元素    下面该研究WriteIt 方法中处理元素节点和嵌入在其中的属性的部分 ,代码示意如下:    ntELEMENT_NODE :    begin      // 输出元素起始标记       S := '<' + nodeName;      // 输出元素的属性       attributes := toWrite.Attributes;      attrCount := attributes.Length;      if FBreakoutAttributes then      if Assigned(FElementNodeEvent) then        FElementNodeEvent(Self, Level - AValue, NodeName);        for i := 0 to attrCount - 1 do begin          Attribute := attributes.item(i);          S :=  S + ' ' + attribute.NodeName;          S := S + attribute.NodeValue;          if FBreakoutAttributes then begin            if Assigned(FElementNodeEvent) then              FElementNodeEvent(Self, Level - AValue + 1, attribute.NodeName);            if Assigned(FElementNodeEvent) then              FElementNodeEvent(Self, (Level - AValue) + 2, attribute.NodeValue);            if Assigned(FAnyNodeEvent) then              FAnyNodeEvent(Self, attribute.NodeName + 'Level: ' + IntToStr(Level));            if Assigned(FAnyNodeEvent) then              FAnyNodeEvent(Self, attribute.NodeValue + 'Level: ' + IntToStr(Level));          end;        end;        //  检查是否有子节点         child := toWrite.FirstChild;        if (child <> nil) then begin          // 有子节点,加上结束标记,输出子节点           S := S + '>';          if not FBreakoutAttributes then begin            if Assigned(FElementNodeEvent) then              FElementNodeEvent(Self, Level - AValue, S);            if Assigned(FAnyNodeEvent) then              FAnyNodeEvent(Self, S + 'Level: ' + IntToStr(Level));          end;          // 递归调用           while( child <> nil) do begin            WriteIt(child, Level);            child := child.NextSibling;          end;