libxml解析xml文件的一些總結

介紹:XML 和 DOM
libxml
介紹 數據類型 — xmlChar數據結構 創建 XML 文檔解析 XML 文檔修改 xml 文檔
Xpath — 處理大型 XML 文檔libxml2 庫函數
要注意的函數讀取 xml 文件xml 操作基本結構及其指針類型根節點相關函數 創建子節點相關函數添加子節點相關函數屬性相關函數

參考

  1. http://xmlsoft.org/
  2. http://www.miidoo.cn/info_detail-204.html
  3. http://www.blogjava.net/wxb_nudt/archive/2007/11/28/161340.html
  4. http://www.ibm.com/developerworks/cn/aix/library/au-libxml2.html
  5. http://www.cppblog.com/lymons/archive/2009/03/30/37553.html
  6. XPath 教程

XML

介紹:XML 和 DOM

XML是eXtensible Markup Language的縮寫,它是一種可擴展性標識語言, 能夠讓你自己創造標識,標識你所表示的內容。DOM全稱是Document Object Model(文檔對象模型),定義了一組與平臺和語言無關的接口,以便程序和腳本能夠動態訪問和修改XML文檔內容、結構及樣式。XML創建了標識,而 DOM的作用就是告訴程序如何操作和顯示這些標識。

XML將數據組織成為一棵樹,DOM通過解析XML文檔,為XML文檔在邏輯上建立一個樹模型,樹的節點是一個個的對象。這樣通過操作這棵樹和這些對象就可以完成對XML文檔的操作,為處理文檔的所有方面提供了一個完美的概念性框架。

XML 中共有12種節點類型,其中最常見的節點類型有5種:

元素
元素是 XML 的基本組成單元。,描述XML的基本信息。
屬性
屬性節點包含關于元素節點的信息,通常包含在元素里面,描述元素的屬性。
文本
包含許多文本信息或者只是空白。
文檔
文檔節點是整個文檔中所有其它節點的父節點。
注釋
注釋是對相關的信息進行描述、注釋。

libxml

介紹

本文所介紹的 libxml 是針對 C 語言的一套 API 接口。其他如 ruby,python 亦有對應的基于 libxml 開發的綁定庫接口。

數據類型 — xmlChar

在 libXml 中用 xmlChar 替代 char , XML 使用 UTF-8 編碼的一字節字符串。如果你的數據使用其它編碼,它必須被轉換到 UTF-8 才能使用libxml的函數。

如同標準 C 中的 char 類型一樣, xmlChar 也有動態內存分配、字符串操作等相關函數。例如 xmlMalloc 是動態分配內存的函數; xmlFree 是配套的釋放內存函數; xmlStrcmp 是字符串比較函數等等。基本上 xmlChar 字符串相關函數都在xmlstring.h 中定義;而動態內存分配函數在 xmlmemory.h 中定義。另外要注意,因為總是要在 xmlChar* 和 char* 之間進行類型轉換,所以定義了一個宏 BAD_CAST ,其定義如下: xmlstring.h

#define BAD_CAST (xmlChar *)

原則上來說, unsigned char 和 char 之間進行強制類型轉換是沒有問題的。

數據結構

xmlDoc
代表DOM結構中的文檔類型。包含由解析文檔建立的樹結構, xmlDocPtr 是指向這個結構的指針。
xmlNode
代表DOM結構中的除文檔類型類型外的其它節點類型。包含單一結點的結構, xmlNodePtr 是指向這個結構的指針,它被用于遍歷文檔樹。節點應該是xml中最重要的元素了, xmlNode 代表了xml文檔中的一個節點,實現為一個 struct ,內容很豐富: tree.h
typedef struct _xmlNode xmlNode;
typedef xmlNode *xmlNodePtr;
struct _xmlNode {
void           *_private;/* application data */
xmlElementType   type;   /* type number, must be second ! */
const xmlChar   *name;      /* the name of the node, or the entity */
struct _xmlNode *children; /* parent->childs link */
struct _xmlNode *last;   /* last child link */
struct _xmlNode *parent;/* child->parent link */
struct _xmlNode *next;   /* next sibling link */
struct _xmlNode *prev;   /* previous sibling link */
struct _xmlDoc *doc;/* the containing document */
/* End of common part */
xmlNs           *ns;        /* pointer to the associated namespace */
xmlChar         *content;   /* the content */
struct _xmlAttr *properties;/* properties list */
xmlNs           *nsDef;     /* namespace definitions on this node */
void            *psvi;/* for type/PSVI informations */
unsigned short   line;   /* line number */
unsigned short   extra; /* extra data for XPath/XSLT */
};

可以看到,節點之間是以鏈表和樹兩種方式同時組織起來的,next和prev指針可以組成鏈表,而parent和children可以組織為樹。所有節點都是文檔 xmlDoc 節點的直接或間接子節點。同時還有以下重要元素:

  • 節點中的文字內容: content ;
  • 節點所屬文檔: doc ;
  • 節點名字: name ;
  • 節點的 namespace: ns ;
  • 節點屬性列表: properties ;

xml 文檔的操作其根本原理就是在節點之間移動、查詢節點的各項信息,并進行增加、刪除、修改的操作。 xmlDocSetRootElement 函數可以將一個節點設置為某個文檔的根節點,這是將文檔與節點連接起來的重要手段,當有了根結點以后,所有子節點就可以依次連接上根節點,從而組織成為一個 xml 樹。

創建 XML 文檔

創建一個 XML 文檔流程如下:

  1. 用 xmlNewDoc 函數創建一個文檔指針 doc;
  2. 用 xmlNewNode 函數創建一個節點指針 root_node;
  3. 用 xmlDocSetRootElement 將 root_node 設置為 doc 的根節點;
  4. 給 root_node 添加一系列子節點,并設置字節點的內容和屬性;
  5. 用 xmlSaveFile 保存 xml 到文件;
  6. 用 xmlFreeDoc 函數關閉文檔指針,清除內存。

示例

下面用一個例子說明一些函數的使用,和創建一個 XML 文檔的大致步驟:

#include <stdio.h>
#include <stdlib.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
int main (int argc, char **argv)
{
xmlDocPtr pdoc = NULL;
xmlNodePtr proot_node = NULL,pnode = NULL,pnode1 = NULL;
// 創建一個新文檔并設置 root 節點
  // 一個 XML 文件只有一個 root 節點
  pdoc = xmlNewDoc (BAD_CAST "1.0");
proot_node = xmlNewNode (NULL, BAD_CAST "根節點");
xmlNewProp (proot_node, BAD_CAST "版本", BAD_CAST "1.0");
xmlDocSetRootElement (pdoc, proot_node);
pnode = xmlNewNode (NULL, BAD_CAST "子節點1");
// 創建上面 pnode 的子節點
  xmlNewChild (pnode, NULL, BAD_CAST "子子節點1", BAD_CAST "信息");
// 添加子節點到 root 節點
  xmlAddChild (proot_node, pnode);
pnode1 = xmlNewNode (NULL, BAD_CAST "子子節點1");
xmlAddChild (pnode, pnode1);
xmlAddChild (pnode1,xmlNewText (BAD_CAST "這是更低的節點,子子子節點1"));
// 還可以這樣直接創建一個子節點到 root 節點上
  xmlNewTextChild (proot_node, NULL, BAD_CAST "子節點2", BAD_CAST "子節點2的內容");
xmlNewTextChild (proot_node, NULL, BAD_CAST "子節點3", BAD_CAST "子節點3的內容");
// 保存 xml 為文件,如果沒有給出文件名參數,就輸出到標準輸出
  xmlSaveFormatFileEnc (argc > 1 ? argv[1]:"-", pdoc, "UTF-8", 1);
// 釋放資源
  xmlFreeDoc (pdoc);
xmlCleanupParser ();
xmlMemoryDump ();
return 0;
}

編譯這個例子,先看看系統里面的 libxml2 庫的 pkgconfig 信息:

root@jianlee:~/lab/xml# cat /usr/lib/pkgconfig/libxml-2.0.pc
prefix=/usr
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
modules=1
Name: libXML
Version: 2.6.32
Description: libXML library version2.
Requires:
Libs: -L${libdir} -lxml2
Libs.private:  -lz  -lm
Cflags: -I${includedir}/libxml2
root@jianlee:~/lab/xml# pkg-config libxml-2.0 --cflags --libs
-I/usr/include/libxml2  -lxml2

編譯:

root@jianlee:~/lab/xml# gcc -Wall `pkg-config libxml-2.0 --cflags --libs` create_xml.c

如果沒有修改源程序,輸出應該是這樣:

root@jianlee:~/lab/xml# ./a.out
<?xml version="1.0" encoding="UTF-8"?>
<根節點 版本="1.0">
<子節點1>
<子子節點1>信息</子子節點1>
<子子節點1>這是更低的節點,子子子節點1</子子節點1>
</子節點1>
<子節點2>子節點2的內容</子節點2>
<子節點3>子節點3的內容</子節點3>
</根節點>

示例補充說明

輸出的各節點不要在一行

上面使用下面方式保存 xml 文檔,輸出的文件各子節點間自動加入回車:

  // 保存 xml 為文件,如果沒有給出文件名參數,就輸出到標準輸出
xmlSaveFormatFileEnc (argc > 1 ? argv[1]:"-", pdoc, "UTF-8", 1);

如果把上面的 1 換成 0 ,輸出格式是放在一行。

用到的函數說明

上面涉及幾個函數和類型定義,不過意思很明了,下面解釋一個(重要的是自己動手寫程序,反復實驗,所謂熟能生巧)。

xmlDocPtr
指向 XML 文檔對象的指針
xmlNodePtr
指向 XML 文檔對象中的節點對象(根節點和子節點都是一樣的)
xmlNewDoc
創建一個 XML 文檔對象
xmlNewNode
創建一個 XML 文檔的指針對象
xmlNewProp
給一個節點增加屬性信息,包括在 <> 中,如:
  xmlNewProp (proot_node, BAD_CAST "版本", BAD_CAST "1.0");

最后顯示是這個樣子:

<根節點 版本="1.0">
xmlDocSetRootElement
設置 XML 文檔對象的根節點,只有一個根節點
xmlNewChild
指定一個節點,會創建這個節點的子節點。這樣不需要使用 xmlNewNode 創建一個節點,再使用 xmlAddChild 添加到其父節點中。
xmlAddChild
把一個節點設置為另外一個節點的子節點。
xmlNewText
創建一個描述節點,沒有 <> 符號,需要添加到其他節點上。比如上例中的:
  xmlAddChild (pnode1,xmlNewText (BAD_CAST "這是更低的節點,子子子節點1"));

會出現下面的結果:

    <子子節點1>這是更低的節點,子子子節點1</子子節點1>
xmlNewTextChild
和 xmlNewText 的區別如同 xmlNewNodeChild 和 xmlNewNode 的區別一樣!
xmlSaveFormatFileEnc
保存 xml 對象為文件。
xmlFreeDoc
釋放 xml 對象
xmlCleanupParser
清理
xmlMemoryDump
清理

解析 XML 文檔

解析一個xml文檔,從中取出想要的信息,例如節點中包含的文字,或者某個節點的屬性,其流程如下:

  • 用 xmlReadFile 函數讀出一個文檔指針 doc ;
  • 用 xmlDocGetRootElement 函數得到根節點 curNode ;
  • curNode->xmlChildrenNode 就是根節點的子節點集合 ;
  • 輪詢子節點集合,找到所需的節點,用 xmlNodeGetContent 取出其內容 ;
  • 用 xmlHasProp 查找含有某個屬性的節點 ;
  • 取出該節點的屬性集合,用 xmlGetProp 取出其屬性值 ;
  • 用 xmlFreeDoc 函數關閉文檔指針,并清除本文檔中所有節點動態申請的內存。

注意: 節點列表的指針依然是 xmlNodePtr ,屬性列表的指針也是 xmlAttrPtr ,并沒有 xmlNodeList 或者 xmlAttrList 這樣的類型 。看作列表的時候使用它們的 next 和 prev 鏈表指針來進行輪詢 。只有在 Xpath 中有 xmlNodeSet 這種類型。

示例

#include <stdio.h>
#include <stdlib.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
int main (int argc , char **argv)
{
xmlDocPtr     pdoc = NULL;
xmlNodePtr    proot = NULL, curNode = NULL;
char *psfilename;
if (argc < 1)
{
printf ("用法: %s xml文件名\n", argv[0]);
exit (1);
}
psfilename = argv[1];
// 打開 xml 文檔
  //xmlKeepBlanksDefault(0);
  pdoc = xmlReadFile (psfilename, "UTF-8", XML_PARSE_RECOVER);
if (pdoc == NULL)
{
printf ("打開文件 %s 出錯!\n", psfilename);
exit (1);
}
// 獲取 xml 文檔對象的根節對象
  proot = xmlDocGetRootElement (pdoc);
if (proot == NULL)
{
printf("錯: %s 是空文檔(沒有root節點)!\n", psfilename);
exit (1);
}
/* 我使用上面程序創建的 xml 文檔,它的根節點是“根節點”,這里比較是否
正確。*/
if (xmlStrcmp (proot->name, BAD_CAST "根節點") != 0)
{
printf ("錯誤文檔" );
exit (1);
}
/* 如果打開的 xml 對象有 version 屬性,那么就輸出它的值。 */
if (xmlHasProp (proot, BAD_CAST "版本"))
{
xmlChar *szAttr = xmlGetProp (proot, BAD_CAST "版本");
printf ("版本: %s \n根節點:%s\n" , szAttr, proot->name);
}
else
{
printf (" xml 文檔沒有版本信息\n");
}
curNode = proot->xmlChildrenNode;
char n=0;
while (curNode != NULL)
{
if (curNode->name != BAD_CAST "text")
{
printf ("子節點%d: %s\n", n++,curNode->name);
}
curNode = curNode->next;
}
/* 關閉和清理 */
xmlFreeDoc (pdoc);
xmlCleanupParser ();
return 0;
}

編譯運行(使用上例創建的 my.xml 文件):

root@jianlee:~/lab/xml# cat my.xml
<?xml version="1.0" encoding="UTF-8"?>
<根節點 版本="1.0">
<子節點1>
<子子節點1>信息</子子節點1>
<子子節點1>這是更低的節點,子子子節點1</子子節點1>
</子節點1>
<子節點2>子節點2的內容</子節點2>
<子節點3>子節點3的內容</子節點3>
</根節點>
root@jianlee:~/lab/xml# gcc -Wall `pkg-config libxml-2.0 --cflags --libs` read_xml.c
root@jianlee:~/lab/xml# ./a.out my.xml
版本: 1.0
根節點:根節點
子節點0: text
子節點1: 子節點1
子節點2: text
子節點3: 子節點2
子節點4: text
子節點5: 子節點3
子節點6: text

為什么 my.xml 文件中顯示只有 ”子節點1“、 ”子節點2“和 “子節點3”三個子節點,而程序顯示有 7 個子節點呢?!而且 0、2、4、6 都是 text 名字?

這是因為其他四個分別是元素前后的空白文本符號,而 XML 把它們也當做一個 Node !元素是 Node 的一種類型。XML 文檔對象模型 (DOM) 定義了幾種不同的 Nodes 類型,包括 Elements(如 files 或者 age)、Attributes(如 units)和 Text(如 root 或者 10)。元素可以具有子節點。

在打開 xml 文檔之前加上一句(取消上面程序中的此句注釋就可以):

  xmlKeepBlanksDefault(0);

或者使用下面參數讀取 xml 文檔:

//讀取xml文件時忽略空格
doc = xmlReadFile(docname, NULL, XML_PARSE_NOBLANKS);

這樣就可以按我們所想的運行了:

root@jianlee:~/lab/xml# gcc -Wall `pkg-config libxml-2.0 --cflags --libs` read_xml.c
root@jianlee:~/lab/xml# ./a.out my.xml
版本: 1.0
根節點:根節點
子節點0: 子節點1
子節點1: 子節點2
子節點2: 子節點3

還有一點注意: my.xml 文件中的子節點名字一次是 “子節點1”、“子節點2”、 “子節點3”。程序中的 n 值確是從 0 開始計算。從 0 還是 1 是個人喜好。我有時候喜好從 0 開始,有時候喜好從 1 開始。

xmlFreeDoc
釋放文檔指針。特別注意,當你調用 xmlFreeDoc 時,該文檔所有包含的節點內存都被釋放,所以一般來說不需要手動調用 xmlFreeNode 或者 xmlFreeNodeList 來釋放動態分配的節點內存,除非你把該節點從文檔中移除了。一般來說,一個文檔中所有節點都應該動態分配,然后加入文檔,最后調用 xmlFreeDoc 一次釋放所有節點申請的動態內存,這也是為什么我們很少看見 xmlNodeFree 的原因。
xmlSaveFile
將文檔以默認方式存入一個文件。
xmlSaveFormatFileEnc
可將文檔以某種編碼/格式存入一個文件中,創建 xml 文檔是的示例中用到

修改 xml 文檔

首先打開一個已經存在的xml文檔,順著根結點找到需要添加、刪除、修改的地方,調用相應的xml函數對節點進行增、刪、改操作。

刪除節點

刪除節點使用下面方法:

if (!xmlStrcmp(curNode->name, BAD_CAST "newNode1"))
{
xmlNodePtr tempNode;
tempNode = curNode->next;
xmlUnlinkNode(curNode);
xmlFreeNode(curNode);
curNode = tempNode;
continue;
}

即將當前節點從文檔中斷鏈(unlink),這樣本文檔就不會再包含這個子節點。這樣做需要使用一個臨時變量來存儲斷鏈節點的后續節點,并記得要手動刪除斷鏈節點的內存。

示例

#include <stdio.h>
#include <stdlib.h>
#include <libxml/parser.h>
int main(int argc, char* argv[])
{
xmlDocPtr doc;   //定義解析文檔指針
  xmlNodePtr curNode;  //定義結點指針(你需要它為了在各個結點間移動)
  char *szDocName;
if (argc <= 1)
{
printf("Usage: %s docname\n", argv[0]);
return(0);
}
szDocName = argv[1];
xmlKeepBlanksDefault(0);
doc = xmlReadFile(szDocName,"UTF-8",XML_PARSE_RECOVER);  //解析文件

if (NULL == doc)
{
fprintf(stderr,"Document not parsed successfully. \n");
return -1;
}
curNode = xmlDocGetRootElement(doc);
/*檢查確認當前文檔中包含內容*/
if (NULL == curNode)
{
fprintf(stderr,"empty document\n");
xmlFreeDoc(doc);
return -1;
}
curNode = curNode->children;
while (NULL != curNode)
{
//刪除 "子節點1"
      if (!xmlStrcmp(curNode->name, BAD_CAST "子節點1"))
{
xmlNodePtr tempNode;
tempNode = curNode->next;
xmlUnlinkNode(curNode);
xmlFreeNode(curNode);
curNode = tempNode;
continue;
}
//修改 "子節點2" 的屬性值
      if (!xmlStrcmp(curNode->name, BAD_CAST "子節點2"))
{
xmlSetProp(curNode,BAD_CAST "屬性1", BAD_CAST "設置");
}
//修改 “子節點2” 的內容
      if (!xmlStrcmp(curNode->name, BAD_CAST "子節點2"))
{
xmlNodeSetContent(curNode, BAD_CAST "內容變了");
}
//增加一個屬性
      if (!xmlStrcmp(curNode->name, BAD_CAST "子節點3"))
{
xmlNewProp(curNode, BAD_CAST "新屬性", BAD_CAST "有");
}
//增加 "子節點4"
      if (!xmlStrcmp(curNode->name, BAD_CAST "子節點3"))
{
xmlNewTextChild(curNode, NULL, BAD_CAST "新子子節點1", BAD_CAST "新內容");
}
curNode = curNode->next;
}
//  保存文件
  xmlSaveFormatFileEnc (szDocName, doc,"UTF-8",1);
xmlFreeDoc (doc);
xmlCleanupParser ();
xmlMemoryDump ();
return 0;
}

編譯運行:

root@jianlee:~/lab/xml# cat my.xml
<?xml version="1.0" encoding="UTF-8"?>
<根節點 版本="1.0">
<子節點1>
<子子節點1>信息</子子節點1>
<子子節點1>這是更低的節點,子子子節點1</子子節點1>
</子節點1>
<子節點2>子節點2的內容</子節點2>
<子節點3>子節點3的內容</子節點3>
</根節點>
root@jianlee:~/lab/xml# gcc -Wall `pkg-config libxml-2.0 --cflags --libs` modify_xml.c
root@jianlee:~/lab/xml# ./a.out my.xml
root@jianlee:~/lab/xml# cat my.xml
<?xml version="1.0" encoding="UTF-8"?>
<根節點 版本="1.0">
<子節點2 屬性1="設置">內容變了</子節點2>
<子節點3 新屬性="有">子節點3的內容<新子子節點1>新內容</新子子節點1></子節點3>
</根節點>
root@jianlee:~/lab/xml# ./a.out my.xml  # 看看再運行一次的結果!
root@jianlee:~/lab/xml# cat my.xml
<?xml version="1.0" encoding="UTF-8"?>
<根節點 版本="1.0">
<子節點2 屬性1="設置">內容變了</子節點2>
<子節點3 新屬性="有" 新屬性="有">子節點3的內容<新子子節點1>新內容</新子子節點1><新子子節點1>新內容</新子子節點1></子節點3>
</根節點>

Xpath — 處理大型 XML 文檔

libxml2 庫函數

要注意的函數

xmlKeepBlanksDefault

int xmlKeepBlanksDefault (int val)

設置是否忽略空白節點,比如空格,在分析前必須調用,默認值是0,最好設置成1.

xmlKeepBlanksDefault(0) 除了在讀入xml文件時忽略空白之外,還會在寫出xml 文件時在每行前面放置縮進(indent)。如果使用xmlKeepBlanksDefault(1) 則你會發現每行前面的縮進就沒有了,但不會影響回車換行。

xmlSaveFormatFile

  // 保存 xml 為文件,如果沒有給出文件名參數,就輸出到標準輸出
xmlSaveFormatFileEnc (argc > 1 ? argv[1]:"-", pdoc, "UTF-8", 1);

xmlSaveFormatFile 的 format 參數設置成 0,保存后的 xml 文檔里是會把所有的結點都放到一行里顯示。設置為 1,就可以自動添加回車。

讀取 xml 文件

xmlParseFile

xmlDocPtr xmlParseFile (const char * filename)

以默認方式讀入一個 UTF-8 格式的 xml 文檔, 并返回一個文檔對象指針 <libxml/tree.h>

xmlReadFile

指定編碼讀取一個 xml 文檔,返回指針。

xml 操作基本結構及其指針類型

xmlDoc, xmlDocPtr

文檔對象的結構體及其指針

xmlNode, xmlNodePtr

節點對象的結構體及其指針

xmlAttr, xmlAttrPtr

節點屬性的結構體及其指針

xmlNs, xmlNsPtr

節點命名空間的結構及其指針

根節點相關函數

xmlDocGetRootElement

xmlNodePtr xmlDocGetRootElement (xmlDocPtr doc)
獲取文檔根節點

xmlDocSetRootElement

xmlNodePtr xmlDocSetRootElement (xmlDocPtr doc, xmlNodePtr root)
設置文檔根節點

創建子節點相關函數

xmlNewNode

xmlNodePtr xmlNewNode (xmlNsPtr ns, const xmlChar * name)
創建新節點

xmlNewChild

xmlNodePtr xmlNewChild (xmlNodePtr parent, xmlNsPtr ns, const xmlChar * name, const xmlChar * content)
創建新的子節點

xmlCopyNode

xmlNodePtr xmlCopyNode (const xmlNodePtr node, int extended)
復制當前節點

添加子節點相關函數

xmlAddChild

xmlNodePtr xmlAddChild (xmlNodePtr parent, xmlNodePtr cur)
給指定節點添加子節點

xmlAddNextSibling

xmlNodePtr xmlAddNextSibling (xmlNodePtr cur, xmlNodePtr elem)
添加后一個兄弟節點

xmlAddPrevSibling

xmlNodePtr xmlAddPrevSibling (xmlNodePtr cur, xmlNodePtr elem)
添加前一個兄弟節點

xmlAddSibling

xmlNodePtr xmlAddSibling (xmlNodePtr cur, xmlNodePtr elem)
添加兄弟節點

屬性相關函數

xmlNewProp

xmlAttrPtr xmlNewProp (xmlNodePtr node, const xmlChar * name, const xmlChar * value)
創建新節點屬性

xmlGetProp

xmlChar * xmlGetProp (xmlNodePtr node, const xmlChar * name)
讀取節點屬性

xmlSetProp

xmlAttrPtr xmlSetProp (xmlNodePtr node, const xmlChar * name, const xmlChar * value)
設置節點屬性

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/444979.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/444979.shtml
英文地址,請注明出處:http://en.pswp.cn/news/444979.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux(7)-正則表達式

正則表達式demo1:在某個文件中尋找命令seddemo2:尋找8位電話號碼正則表達式&#xff1a;用來描述或者匹配某一系列符合某個句法隊則的字符串或者單個字符串。最初正則表達式&#xff0c;出現在自動控制理論和形式化語言理論中。 Linux 中 find grep sed ls命令都支持正則表達式…

服務器端開發的一些建議

摘要: 本文作為游戲服務器端開發的基本大綱&#xff0c;是游戲實踐開發中的總結。第一部分專業基礎&#xff0c;用于指導招聘和實習考核&#xff0c; 第二部分游戲入門&#xff0c;講述游戲服務器端開發的基本要點&#xff0c;第三部分服務端架構&#xff0c;介紹架構設計中的一…

leetcode63 不同路徑II

一個機器人位于一個 m x n 網格的左上角 &#xff08;起始點在下圖中標記為“Start” &#xff09;。 機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角&#xff08;在下圖中標記為“Finish”&#xff09;。 現在考慮網格中有障礙物。那么從左上角到右下角將…

小談Online-game服務器端設計(1、2)

談這個話題之前&#xff0c;首先要讓大家知道&#xff0c;什么是服務器。在網絡游戲中&#xff0c;服務器所扮演的角色是同步&#xff0c;廣播和服務器主動的一些行為&#xff0c;比如說天氣&#xff0c;NPC AI之類的&#xff0c;之所以現在的很多網絡游戲服務器都需要負擔一些…

Linux(8)-Linux下的編程開發-C/C++、PHP、JAVA概述

Linux下的編程開發1.C/C語言開發環境的搭建2.PHP開發環境搭建3.JAVA開發環境搭建1.C/C語言開發環境的搭建 方式1:文本編輯器編譯器&#xff08;gcc/g&#xff09; Ubuntu 下常用的文本編輯器&#xff1a; Gedit–語法高亮Vim–vi(無比強大無比難用)的改進。字符界面/圖形界面…

leetcode55 跳躍游戲 秒殺所有答案

給定一個非負整數數組&#xff0c;你最初位于數組的第一個位置。 數組中的每個元素代表你在該位置可以跳躍的最大長度。 判斷你是否能夠到達最后一個位置。 示例 1: 輸入: [2,3,1,1,4] 輸出: true 解釋: 我們可以先跳 1 步&#xff0c;從位置 0 到達 位置 1, 然后再從位置 …

小談Online-game服務器端設計(3)

下面我想來談談關于服務器上NPC的設計以及NPC智能等一些方面涉及到的問題。首先&#xff0c;我們需要知道什么是NPC&#xff0c;NPC需要做什么。NPC的全稱是&#xff08;Non-Player Character&#xff09;&#xff0c;很顯然&#xff0c;他是一個character&#xff0c;但不是玩…

小談Online-game服務器端設計(4)

在這一章節&#xff0c;我想談談關于服務器端的腳本的相關設計。因為在上一章節里面&#xff0c;談NPC智能相關的時候已經接觸到一些腳本相關的東東了。還是先來談談腳本的作用吧。   在基于編譯的服務器端程序中&#xff0c;是無法在程序的運行過程中構建一些東西的&#xf…

leetcode45 跳躍游戲II 秒殺所有答案

給定一個非負整數數組&#xff0c;你最初位于數組的第一個位置。 數組中的每個元素代表你在該位置可以跳躍的最大長度。 你的目標是使用最少的跳躍次數到達數組的最后一個位置。 示例: 輸入: [2,3,1,1,4] 輸出: 2 解釋: 跳到最后一個位置的最小跳躍數是 2。 從下標為 …

MachineLearning(7)-決策樹基礎+sklearn.DecisionTreeClassifier簡單實踐

sklearn.DecisionTreeClassifier決策樹簡單使用1.決策樹算法基礎2.sklearn.DecisionTreeClassifier簡單實踐2.1 決策樹類2.3 決策樹構建2.3.1全數據集擬合&#xff0c;決策樹可視化2.3.2交叉驗證實驗2.3.3超參數搜索2.3.4模型保存與導入2.3.5固定隨機數種子參考資料1.決策樹算法…

游戲服務器體系結構

本文描述了一個我所設計的游戲服務器體系結構,其目的是實現游戲服務器的動態負載平衡,將對象從繁忙的服務器轉移到相對空閑的服務器中.設計并沒有經過具體的測試與驗證,僅僅是將自己目前的一些想法記錄下來.隨著新構思的出現,可能會有所變化. 以下是服務器的邏輯視圖,其中忽略…

游戲服務器架構探討

要描述一項技術或是一個行業&#xff0c;一般都會從其最古老的歷史開始說起&#xff0c;我本也想按著這個套路走&#xff0c;無奈本人乃一八零后小輩&#xff0c;沒有經歷過那些苦澀的卻令人羨慕的單機游戲開發&#xff0c;也沒有響當當的拿的出手的優秀作品&#xff0c;所以也…

leetcode72 編輯距離

給定兩個單詞 word1 和 word2&#xff0c;計算出將 word1 轉換成 word2 所使用的最少操作數 。 你可以對一個單詞進行如下三種操作&#xff1a; 插入一個字符 刪除一個字符 替換一個字符 示例 1: 輸入: word1 "horse", word2 "ros" 輸出: 3 解釋: ho…

即時通訊系統架構

有過幾款IM系統開發經歷&#xff0c;目前有一款還在線上跑著。準備簡單地介紹一下大型商業應用的IM系統的架構。設計這種架構比較重要的一點是低耦合&#xff0c;把整個系統設計成多個相互分離的子系統。我把整個系統分成下面幾個部分&#xff1a;&#xff08;1&#xff09;狀態…

leetcode303 區域和檢索

給定一個整數數組 nums&#xff0c;求出數組從索引 i 到 j (i ≤ j) 范圍內元素的總和&#xff0c;包含 i, j 兩點。 示例&#xff1a; 給定 nums [-2, 0, 3, -5, 2, -1]&#xff0c;求和函數為 sumRange() sumRange(0, 2) -> 1 sumRange(2, 5) -> -1 sumRange(0,…

算法(24)-股票買賣

股票買賣1.動態規劃框架LeetCode-121 一次買賣LeetCode-122 不限次數LeetCode-309 不限次數冷凍期LeetCode-714 不限次數手續費LeetCode-123 兩次買賣LeetCode-188 k次買賣2.貪心特解LeetCode-121 一次買賣LeetCode-122 不限次數解題思路參考buladong解題&#xff0c;詳細信息可…

網絡游戲的客戶端同步問題 .

有關位置同步的方案實際上已經比較成熟&#xff0c;網上也有比較多的資料可供參考。在《帶寬限制下的視覺實體屬性傳播》一文中&#xff0c;作者也簡單提到了位置同步方案的構造過程&#xff0c;但涉及到細節的地方沒有深入&#xff0c;這里專門針對這一主題做些回顧。 最直接的…

leetcode319 燈泡的開關

初始時有 n 個燈泡關閉。 第 1 輪&#xff0c;你打開所有的燈泡。 第 2 輪&#xff0c;每兩個燈泡你關閉一次。 第 3 輪&#xff0c;每三個燈泡切換一次開關&#xff08;如果關閉則開啟&#xff0c;如果開啟則關閉&#xff09;。第 i 輪&#xff0c;每 i 個燈泡切換一次開關。 …

網游服務器端設計思考:心跳設計

網絡游戲服務器的主要作用是模擬整個游戲世界&#xff0c;客戶端用過網絡連接把一些信息數據發給服務器&#xff0c;在操作合法的情況下&#xff0c;更新服務器上該客戶端對應的player實體、所在場景等&#xff0c;并把這些操作及其影響廣播出去。讓別的客戶端能顯示這些操作。…

算法(25)-括號

各種括號1.LeetCode-22 括號生成--各種括號排列組合2.LeetCode-20 有效括號(是否)--堆棧3.LeetCode-32 最長有效括號(長度)--dp4.LeetCode-301刪除無效括號 --多種刪除方式1.LeetCode-22 括號生成–各種括號排列組合 數字 n 代表生成括號的對數&#xff0c;請你設計一個函數&a…