XML als Datenbank nutzen

Der TwinCAT Database Server bietet die Möglichkeit eine XML-Datei als Datenbank zu verwenden. Bis auf die Stored Procedure Funktionen werden alle bekannten Funktionsbausteine für das Lesen und Schreiben in eine Datenbank von dem XML-Datenbanktyp unterstützt. Selbst SQL-Befehle, die mit den Funktionsbausteinen FB_DBRecordInsert oder FB_DBRecordSelect abgesetzt werden können, werden vom TwinCAT Database Server interpretiert und entsprechend auf die XML-Datei angewendet.

In diesem Beispiel wird demonstriert, wie eine XML-Datenbank erzeugt, mit dem Baustein FB_DBWrite befüllt und anschließend mit einem SQL-SELECT Befehl und dem FB_DBRecordSelect wieder ausgelesen wird.

Download "Beispiel mit XML als Datenbank nutzen" sample12.zip

XML als Datenbank nutzen 1:

Verwendeter Datenbanktyp

XML

Kompatible Datenbanktypen

MS SQL, MS Compact SQL, MS Access, XML

Verwendete Funktionsbausteine

FB_DBCreate, FB_DBConnectionAdd, FB_DBTableCreate, FB_DBWrite, FB_DBRecordSelect

Einzubindende Bibliotheken

"TcDatabase.lib", "TcSystem.lib", "TcBase.lib", "STANDARD.lib",  "TcUtilities.lib"

Download Dateiliste

XML_DatabaseType.pro

MAIN Programm

PROGRAM MAIN
VAR
    nState:BYTE := 0;

    R_TRIG1: R_TRIG;
    bSTART: BOOL;

    nCounter: INT;

    FB_FileDelete1: FB_FileDelete;
    FB_DBCreate1: FB_DBCreate;
    FB_DBConnectionAdd1: FB_DBConnectionAdd;
    FB_DBTableCreate1: FB_DBTableCreate;
    FB_DBWrite1: FB_DBWrite;
    FB_DBRecordSelect1: FB_DBRecordSelect;

    bBusy_Delete: BOOL;
    bBusy_CreateDB: BOOL;
    bBusy_ConnAdd: BOOL;
    bBusy_CreateTable: BOOL;
    bBusy_WriteDB: BOOL;
    bBusy_SelectRecord: BOOL;

    bErr: BOOL;
    nErrid: UDINT;
    stSQLState: ST_DBSQLError;
    nRecs: UDINT;

    nDBid: UDINT;

    arrTablestrc: ARRAY [0..3] OF ST_DBColumnCfg := (sColumnName:='ID',sColumnProperty:='IDENTITY(1,1)',eColumnType:=EDBCOLUMN_BIGINT),
                    (sColumnName:='Timestamp',eColumnType:=EDBCOLUMN_DATETIME),
                    (sColumnName:='Name',sColumnProperty:='80',eColumnType:=EDBCOLUMN_NTEXT),
                    (sColumnName:='Value',eColumnType:=EDBCOLUMN_FLOAT);

    rTestValue : LREAL := 1234.56789;
    stRecord: ST_Record;
END_VAR

 

CASE nState OF
    0:
        (*To start this sample you have to set a rising edge to the variable bSTART*)
        R_TRIG1(CLK:=bSTART);
        IF R_TRIG1.Q THEN
            nState := 1;
            FB_FileDelete1(bExecute:=FALSE);
            FB_DBCreate1(bExecute:=FALSE);
            FB_DBConnectionAdd1(bExecute:=FALSE);
            FB_DBTableCreate1(bExecute:=FALSE);
            FB_DBWrite1(bExecute:=FALSE);
            FB_DBRecordSelect1(bExecute:=FALSE);
            bSTART := FALSE;
            nCounter := 0;
        END_IF
    1:
        (*It isn't possible to overwrite an existing database file. If the database file exist the FB_FileDelete block will delete the file*)
        FB_FileDelete1(
            sNetId:= ,
            sPathName:= 'C:\TwinCAT\TcDatabaseSrv\Samples\XMLTestDB.xml',
            ePath:= PATH_GENERIC,
            bExecute:= TRUE,
            tTimeout:= T#5s,
            bBusy=> bBusy_Delete,
            bError=> ,
            nErrId=> );

        IF NOT bBusy_Delete THEN
            nState := 10;
        END_IF
    10:
        (*It isn't possible to overwrite an existing database file. If the database file exist the FB_FileDelete block will delete the file*)
        FB_FileDelete1(
            sNetId:= ,
            sPathName:= 'C:\TwinCAT\TcDatabaseSrv\Samples\XMLTestDB.xsd',
            ePath:= PATH_GENERIC,
            bExecute:= TRUE,
            tTimeout:= T#5s,
            bBusy=> bBusy_Delete,
            bError=> ,
            nErrId=> );

        IF NOT bBusy_Delete THEN
            FB_FileDelete1(bExecute:=FALSE);
            nState := 2;
        END_IF
    2:
        (*The FB_DBCreate block will create the database file "C:\TwinCAT\TcDatabaseSrv\Samples\XMLTestDB.xml" and C:\TwinCAT\TcDatabaseSrv\Samples\XMLTestDB.xsd "*)
        FB_DBCreate1(
            sNetID:= ,
            sPathName:= 'C:\TwinCAT\TcDatabaseSrv\Samples',
            sDBName:= 'XMLTestDB',
            eDBType:= eDBType_XML,
            bExecute:= TRUE,
            tTimeout:= T#15s,
            bBusy=> bBusy_CreateDB,
            bError=> bErr,
            nErrID=> nErrid);

        IF NOT bBusy_CreateDB AND NOT bErr THEN
            nState := 3;
        END_IF
    3:
        (*The FB_DBConnectionAdd adds the connection information to the XML - configuration file*)
        (*ATTENTION: Each database type has his own connection information*)
        FB_DBConnectionAdd1(
            sNetID:= ,
            eDBType:= eDBType_XML,
            eDBValueType:= eDBValue_Double,
            sDBServer:= 'XMLTestDB',
            sDBProvider:= ,
            sDBUrl:= 'C:\TwinCAT\TcDatabaseSrv\Samples\XMLTestDB.xml',
            sDBTable:= 'myTable',
            bExecute:= TRUE,
            tTimeout:= T#15s,
            bBusy=> bBusy_ConnAdd,
            bError=> bErr,
            nErrID=> nErrid,
            hDBID=> nDBid);

        IF NOT bBusy_ConnAdd AND NOT bErr THEN
            nState := 4;
        END_IF
    4:
        (*The FB_DBTableCreate create the table "myTable"*)
        FB_DBTableCreate1(
            sNetID:= ,
            hDBID:= nDBid,
            sTableName:= 'myTable',
            cbTableCfg:= SIZEOF(arrTablestrc),
            pTableCfg:= ADR(arrTablestrc),
            bExecute:= TRUE,
            tTimeout:= T#15s,
            bBusy=> bBusy_CreateTable,
            bError=> bErr,
            nErrID=> nErrid);

        IF NOT bBusy_CreateTable AND NOT bErr THEN
            nState := 5;
        END_IF
    5:
        (*The FB_DBWrite write five times the value of the plc variable "rTestValue" to the database table "myTable"*)
        FB_DBWrite1(
            sNetID:= ,
            hDBID:= nDBid,
            hAdsID:= 1,
            sVarName:= 'MAIN.rTestValue',
            nIGroup:= ,
            nIOffset:= ,
            nVarSize:= ,
            sVarType:= ,
            sDBVarName:= 'rTestValue',
            eDBWriteMode:= eDBWriteMode_Append,
            tRingBufferTime:= ,
            nRingBufferCount:= ,
            bExecute:= TRUE,
            tTimeout:= T#15s,
            bBusy=> bBusy_WriteDB,
            bError=> bErr,
            nErrID=> nErrid,
            sSQLState=> stSQLState);

        IF NOT bBusy_WriteDB AND NOT bErr THEN
            FB_DBWrite1(bExecute := FALSE);
            nCounter := nCounter + 1;
            IF nCounter = 5 THEN
                nState := 6;
            END_IFEND_IF
    6:
        (*The FB_DBRecordSelect select one record of the database table "myTable""*)
        FB_DBRecordSelect1(
            sNetID:= ,
            hDBID:= nDBid,
            sSelectCmd:= 'SELECT * FROM myTable WHERE Name = $'rTestValue$'',
            nRecordIndex:= 0,
            cbRecordSize:= SIZEOF(stRecord),
            pDestAddr:= ADR(stRecord),
            bExecute:= TRUE,
            tTimeout:= T#15s,
            bBusy=> bBusy_SelectRecord,
            bError=> bErr,
            nErrID=> nErrid,
            sSQLState=> stSQLState,
            nRecords=> nRecs);

        IF NOT bBusy_SelectRecord AND NOT bErr THEN
            nState := 0;
        END_IFEND_CASE

Mit einer Positiven Flanke an der Toggle Variable bSTART wird der Ablauf gestartet.

Folgende Dateien werden erzeugt:

XMLTestDB.xml (XML Datenbank Datei)

<?xml version="1.0" encoding="UTF-8"?>
<XMLTestDB xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="XMLTestDB.xsd">
  <myTable>
    <row ID="1" Timestamp="2012-05-10T13:48:47" Name="rTestValue" Value="1234.56789" />
    <row ID="2" Timestamp="2012-05-10T13:48:47" Name="rTestValue" Value="1234.56789" />
    <row ID="3" Timestamp="2012-05-10T13:48:47" Name="rTestValue" Value="1234.56789" />
    <row ID="4" Timestamp="2012-05-10T13:48:47" Name="rTestValue" Value="1234.56789" />
    <row ID="5" Timestamp="2012-05-10T13:48:47" Name="rTestValue" Value="1234.56789" />
 </myTable>
</XMLTestDB>

XMLTestDB.xsd (XML Schema)

<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <xsd:simpleType name="bigint">
    <xsd:restriction base="xsd:long" />
  </xsd:simpleType>
  <xsd:simpleType name="datetime">
    <xsd:restriction base="xsd:dateTime" />
  </xsd:simpleType>
  <xsd:simpleType name="ntext_80">
    <xsd:restriction base="xsd:string">
      <xsd:maxLength value="80" />
    </xsd:restriction>
  </xsd:simpleType>
  <xsd:simpleType name="float">
    <xsd:restriction base="xsd:double" />
  </xsd:simpleType>
  <xsd:complexType name="myTable_Type">
    <xsd:sequence>
      <xsd:element minOccurs="0" maxOccurs="unbounded" name="row">
        <xsd:complexType>
          <xsd:attribute name="ID" type="bigint" />
          <xsd:attribute name="Timestamp" type="datetime" />
          <xsd:attribute name="Name" type="ntext_80" />
          <xsd:attribute name="Value" type="float" />
        </xsd:complexType>
      </xsd:element>
    </xsd:sequence>
  </xsd:complexType>
  <xsd:element name="XMLTestDB">
    <xsd:complexType>
      <xsd:sequence minOccurs="1" maxOccurs="1">
        <xsd:element name="myTable" type="myTable_Type" />
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>