Properties.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 # -*- coding: euc-jp -*-
00003   
00004 
00005 ##
00006 # @file Properties.py
00007 # @brief Property list class (derived from Java Properties)
00008 # @date $Date: $
00009 # @author Noriaki Ando <n-ando@aist.go.jp> and Shinji Kurihara
00010 #
00011 # Copyright (C) 2006-2008
00012 #     Task-intelligence Research Group,
00013 #     Intelligent Systems Research Institute,
00014 #     National Institute of
00015 #         Advanced Industrial Science and Technology (AIST), Japan
00016 #     All rights reserved.
00017 
00018 
00019 import sys
00020 import string
00021 
00022 import OpenRTM_aist
00023 
00024 
00025 ##
00026 # @if jp
00027 #
00028 # @class Properties
00029 # @brief プロパティセットを表現するクラス
00030 #
00031 # Properties クラスは、不変のプロパティセットを表す。 Properties をストリーム
00032 # に保管したり、ストリームからロードしたりすることができる。
00033 # プロパティリストの各キー、およびそれに対応する値は文字列となっている。
00034 #
00035 # プロパティリストには、その「デフォルト値」として別のプロパティリストを持つ
00036 # ことができる。元のプロパティリストでプロパティキーが見つからないと、この
00037 # 2番目のプロパティリストが検索される。 
00038 #
00039 # プロパティの取得には getProperty() 、プロパティのセットには setProperty() と
00040 # いったメソッドを使用することが推奨される。
00041 #
00042 # プロパティをストリームに保存するとき、またはストリームからロードするとき
00043 # に、ISO 8859-1 文字エンコーディングが使用される。このエンコーディングに
00044 # 直接表示できない文字は、扱うことができない。
00045 #
00046 # このクラスは、Java の Properties クラス (java.util.Properties) とほぼ同様の
00047 # メソッドを持つ。また、入出力されるファイルは Java の Properties クラスが
00048 # 出力するものと互換性があるが、Unicode を含むものは扱うことができない。
00049 #
00050 # @since 0.4.0
00051 #
00052 # @else
00053 #
00054 # @class Properties
00055 #
00056 # The Properties class represents a persistent set of properties. The
00057 # Properties can be saved to a stream or loaded from a stream. Each key and
00058 # its corresponding value in the property list is a string. 
00059 #
00060 # A property list can contain another property list as its "defaults"; this
00061 # second property list is searched if the property key is not found in the
00062 # original property list. 
00063 #
00064 # Because Properties inherits from Hashtable, the put and putAll methods can
00065 # be applied to a Properties object. Their use is strongly discouraged as 
00066 # they allow the caller to insert entries whose keys or values are not 
00067 # Strings. The setProperty method should be used instead. If the store or 
00068 # save method is called on a "compromised" Properties object that contains a 
00069 # non-String key or value, the call will fail. 
00070 #
00071 # The load and store methods load and store properties in a simple
00072 # line-oriented format specified below. This format uses the ISO 8859-1
00073 # character encoding. Characters that cannot be directly represented in this
00074 # encoding can be written using Unicode escapes ; only a single 'u' character
00075 # is allowed in an escape sequence. The native2ascii tool can be used to
00076 # convert property files to and from other character encodings. 
00077 #
00078 # This class has almost same methods of Java's Properties class. Input and 
00079 # Output stream of this properties are compatible each other except Unicode
00080 # encoded property file.
00081 #
00082 # @endif
00083 class Properties:
00084   """
00085   """
00086 
00087   ##
00088   # @if jp
00089   #
00090   # @brief コンストラクタ
00091   #
00092   # 以下の順に引数をチェックし、インスタンスの生成を行う。
00093   #
00094   # 引数 prop に値が設定されている場合、
00095   # 引数に与えられた Properties のキー、値およびデフォルト値が
00096   # 全てそのままコピーされる。
00097   #
00098   # 引数 key に値が設定されている場合、
00099   # key と value のみを与えて Property のルートノードを作成する。
00100   # 値は全てデフォルト値として設定される。
00101   #
00102   # 引数 defaults_map に値が設定されている場合、
00103   # defaults_map に設定された内容をデフォルト値にもつ Properties を作成する。
00104   # 値は全てデフォルト値として設定される。
00105   # 
00106   # 引数 defaults_str に値が設定されている場合、
00107   # 指定されたデフォルト値を持つ空のプロパティリストを作成する。
00108   # 値は全てデフォルト値として設定される。
00109   # デフォルト値は char* の配列により与えられ、key と value の対になって
00110   # おり、リストの終端は配列の数を表す引数 num か、空文字の key で与えらられ
00111   # なければならない。
00112   # 以下に例を示す。
00113   #
00114   # <pre>
00115   # const char* defaults = {
00116   #     "key1", "value1",
00117   #     "key2", "value2",
00118   #     "key3", "value3",
00119   #     "key4", "value4",
00120   #     "key5", "value5",
00121   #     "" };
00122   # Properties p(defaults);
00123   # // もしくは
00124   # Properties p(defaults, 10);
00125   # </pre>
00126   # 
00127   # @param self
00128   # @param key プロパティのキー(デフォルト値:None)
00129   # @param value プロパティの値(デフォルト値:None)
00130   # @param defaults_map デフォルト値として指定されるmap(デフォルト値:None)
00131   # @param defaults_str デフォルト値を指定する配列(デフォルト値:None)
00132   # @param num デフォルト値を設定する要素数(デフォルト値:None)
00133   # @param prop デフォルト値として指定されるproperty(デフォルト値:None)
00134   # 
00135   # @else
00136   #
00137   # @brief Constructor
00138   #
00139   # All of given Properties's keys, values and default values are copied to
00140   # new Properties.
00141   #
00142   # Creates a root node of Property with root's key and value.
00143   #
00144   # Creates an Properties with default value of std::string map.
00145   #
00146   # Creates an empty property list with the specified defaults.
00147   # The default values are given by array of char*, which should be pairs
00148   # of "key" and "value". The end of list is specified by argument "num",
00149   # which specifies number of array or null character of key.
00150   # The following is an example.
00151   #
00152   # const char* defaults = {
00153   #     "key1", "value1",
00154   #     "key2", "value2",
00155   #     "key3", "value3",
00156   #     "key4", "value4",
00157   #     "key5", "value5",
00158   #     "" };
00159   # Properties p(defaults);
00160   # // or
00161   # Properties p(defaults, 10);
00162   #
00163   # @endif
00164   def __init__(self, key=None, value=None, defaults_map=None, defaults_str=None, num=None, prop=None):
00165     self.default_value = ""
00166     self.root = None
00167     self.empty = ""
00168     self.leaf = []
00169 
00170     # Properties::Properties(const Properties& prop)
00171     if prop:
00172       self.name          = prop.name
00173       self.value         = prop.value
00174       self.default_value = prop.default_value
00175 
00176       keys = prop.propertyNames()
00177       for _key in keys:
00178         node = None
00179         node = prop.getNode(_key)
00180         if node:
00181           self.setDefault(_key, node.default_value)
00182           self.setProperty(_key, node.value)
00183           
00184       return
00185 
00186     # Properties::Properties(const char* key, const char* value)
00187     if key:
00188       self.name = key
00189       if value is None:
00190         self.value = ""
00191       else:
00192         self.value = value
00193       return
00194 
00195     self.name  = ""
00196     self.value = ""
00197 
00198     # Properties::Properties(std::map<std::string, std::string>& defaults)
00199     if defaults_map:
00200       #for i in range(len(defaults_map.items())):
00201       #  self.setDefault(defaults_map.keys()[i], defaults_map.values()[i])
00202       for key, value in defaults_map.items():
00203         self.setDefault(key, value)
00204       return
00205 
00206     if defaults_str:
00207       if num is None:
00208         _num = sys.maxint
00209       else:
00210         _num = num
00211       self.setDefaults(defaults_str, _num)
00212       return
00213 
00214 
00215   ##
00216   # @if jp
00217   # @brief 代入演算子
00218   # 
00219   # 左辺値の Properties のキー、値およびデフォルト値は全て削除され、
00220   # 右辺値の Properties のキー、値およびデフォルト値が全てそのまま
00221   # コピーされる。
00222   # 
00223   # @param self
00224   # @param prop OpenRTM_aist.Properties
00225   # 
00226   # @else
00227   # @brief Assignment operator
00228   # @param self
00229   # @param prop OpenRTM_aist.Properties
00230   # @endif
00231   def assigmentOperator(self, prop):
00232     self.clear()
00233     self.name = prop.name
00234     self.value = prop.value
00235     self.default_value = prop.default_value
00236 
00237     keys = prop.propertyNames()
00238 
00239     for key in keys:
00240       node = None
00241       node = prop.getNode(key)
00242       if node:
00243         self.setDefault(key, node.default_value)
00244         self.setProperty(key, node.value)
00245 
00246     return self
00247 
00248 
00249   ##
00250   # @if jp
00251   #
00252   # @brief デストラクタ
00253   #
00254   # @param self
00255   #
00256   # @else
00257   #
00258   # @brief Destructor
00259   #
00260   # @endif
00261   def __del__(self):
00262     self.clear()
00263     if self.root:
00264       self.root.removeNode(self.name)
00265     return
00266 
00267   #============================================================
00268   # public functions
00269   #============================================================
00270 
00271 
00272   ##
00273   # @if jp
00274   # @brief Name の取得
00275   #
00276   # プロパティの名称を取得する。
00277   #
00278   # @param self
00279   #
00280   # @return プロパティ名
00281   #
00282   # @else
00283   #
00284   # @endif
00285   def getName(self):
00286     return self.name
00287 
00288 
00289   ##
00290   # @if jp
00291   # @brief 値の取得
00292   #
00293   # プロパティの値を取得する。
00294   #
00295   # @param self
00296   #
00297   # @return プロパティ値
00298   #
00299   # @else
00300   #
00301   # @endif
00302   def getValue(self):
00303     return self.value
00304 
00305 
00306   ##
00307   # @if jp
00308   # @brief デフォルト値の取得
00309   #
00310   # プロパティのデフォルト値を取得する。
00311   #
00312   # @param self
00313   #
00314   # @return プロパティデフォルト値
00315   #
00316   # @else
00317   #
00318   # @endif
00319   def getDefaultValue(self):
00320     return self.default_value
00321 
00322 
00323   ##
00324   # @if jp
00325   # @brief 子要素の取得
00326   #
00327   # プロパティの子要素を取得する。
00328   #
00329   # @param self
00330   #
00331   # @return 子要素
00332   #
00333   # @else
00334   #
00335   # @endif
00336   def getLeaf(self):
00337     return self.leaf
00338 
00339 
00340   ##
00341   # @if jp
00342   # @brief ルート要素の取得
00343   #
00344   # プロパティのルート要素を取得する。
00345   #
00346   # @param self
00347   #
00348   # @return ルート要素
00349   #
00350   # @else
00351   #
00352   # @endif
00353   def getRoot(self):
00354     return self.root
00355 
00356 
00357   ##
00358   # @if jp
00359   #
00360   # @brief 指定されたキーを持つプロパティを、プロパティリストから探す
00361   #
00362   # 指定されたキーを持つプロパティを、プロパティリストから探す。
00363   # そのキーがプロパティリストにない場合は、デフォルト値の引数が返される。 
00364   #
00365   # @param self
00366   # @param key プロパティキー
00367   # @param default デフォルト値(デフォルト値:None)
00368   #
00369   # @return 指定されたキー値を持つこのプロパティリストの値
00370   #
00371   # @else
00372   #
00373   # @brief Searches for the property with the specified key in this property
00374   #
00375   # Searches for the property with the specified key in this property list.
00376   # The method returns the default value argument if the property is not 
00377   # found.
00378   #
00379   # @param key the property key
00380   # @param defaultValue a default value. 
00381   #
00382   # @return the value in this property list with the specified key value.
00383   #
00384   # @endif
00385   def getProperty(self, key, default=None):
00386     if default is None:
00387       keys = []
00388       #keys = string.split(key, ".")
00389       self.split(key, ".", keys)
00390 
00391       node = None
00392       node = self._getNode(keys, 0, self)
00393       if node:
00394         if node.value:
00395           return node.value
00396         else:
00397           return node.default_value
00398       return self.empty
00399 
00400     else:
00401       value = self.getProperty(key)
00402       if value:
00403         return value
00404       else:
00405         return default
00406 
00407 
00408   ##
00409   # @if jp
00410   # @brief 指定されたキーに対してデフォルト値を取得する
00411   #
00412   # 指定されたキーを持つプロパティのデフォルト値を返す。
00413   # 指定されたキーを持つプロパティが存在しない場合には空文字を返す。
00414   #
00415   # @param self
00416   # @param key プロパティキー
00417   #
00418   # @return 指定されたキー値を持つプロパティのデフォルト値
00419   #
00420   # @else
00421   # @brief Set value as the default value to specified key's property
00422   # @endif
00423   def getDefault(self, key):
00424     keys = []
00425     #keys = string.split(key, ".")
00426     self.split(key, ".", keys)
00427     node = None
00428     node = self._getNode(keys, 0, self)
00429     if node:
00430       return node.default_value
00431 
00432     return self.empty
00433 
00434 
00435   ##
00436   # @if jp
00437   #
00438   # @brief Properties に value を key について登録する
00439   #
00440   # Properties に value を key について登録する。
00441   # すでに key に対する値を持っている場合、戻り値に古い値を返す。
00442   #
00443   # @param self
00444   # @param key プロパティリストに配置されるキー
00445   # @param value key に対応する値(デフォルト値:None)
00446   #
00447   # @return プロパティリストの指定されたキーの前の値。それがない場合は null
00448   #
00449   # @else
00450   #
00451   # @brief Sets a value associated with key in the property list
00452   #
00453   # This method sets the "value" associated with "key" in the property list.
00454   # If the property list has a value of "key", old value is returned.
00455   #
00456   # @param key the key to be placed into this property list.
00457   # @param value the value corresponding to key. 
00458   #
00459   # @return the previous value of the specified key in this property list,
00460   #         or null if it did not have one.
00461   #
00462   #@endif
00463   def setProperty(self, key, value=None):
00464     if value is not None:
00465       keys = []
00466       #keys = string.split(key, ".")
00467       self.split(key, ".", keys)
00468       curr = self
00469       for _key in keys:
00470         next = curr.hasKey(_key)
00471         if next is None:
00472           next = OpenRTM_aist.Properties(key=_key)
00473           next.root = curr
00474           curr.leaf.append(next)
00475         curr = next
00476       retval = curr.value
00477       curr.value = value
00478       return retval
00479 
00480     else:
00481       self.setProperty(key, self.getProperty(key))
00482       prop = self.getNode(key)
00483       return prop.value
00484 
00485 
00486   ##
00487   # @if jp
00488   # @brief デフォルト値を登録する
00489   #
00490   # key で指定される要素にデフォルト値を登録する。
00491   #
00492   # @param self
00493   # @param key デフォルト値を登録するプロパティのキー
00494   # @param value 登録されるデフォルト値
00495   #
00496   # @return 指定されたデフォルト値
00497   #
00498   # @else
00499   # @brief Sets a default value associated with key in the property list
00500   # @endif
00501   def setDefault(self, key, value):
00502     keys = []
00503     self.split(key, ".", keys)
00504     #keys = string.split(key, ".")
00505 
00506     curr = self
00507     for _key in keys:
00508       next = curr.hasKey(_key)
00509       if next is None:
00510         next = OpenRTM_aist.Properties(key=_key)
00511         next.root = curr
00512         curr.leaf.append(next)
00513       curr = next
00514     if value != "" and value[-1] == "\n":
00515       value = value[0:len(value)-1]
00516     curr.default_value = value
00517     return value
00518 
00519 
00520   ##
00521   # @if jp
00522   # @brief Properties にデフォルト値をまとめて登録する
00523   #
00524   # 配列で指定された要素にデフォルト値をまとめて登録する。
00525   # デフォルト値は char* の配列により与えられ、key と value の対になって
00526   # おり、リストの終端は配列の数を表す引数 num か、空文字の key で与えらられ
00527   # なければならない。
00528   # 
00529   # @param self
00530   # @param defaults デフォルト値を指定する配列
00531   # @param num デフォルト値を設定する要素数(デフォルト値:None)
00532   # 
00533   # @else
00534   # @brief Sets a default value associated with key in the property list
00535   # @endif
00536   def setDefaults(self, defaults, num = None):
00537     if num is None:
00538       num = sys.maxint
00539 
00540     i = 0
00541     len_ = len(defaults)
00542     while 1:
00543       if i > num or i > (len_ - 1) or defaults[i] == "":
00544         break
00545 
00546       key = [defaults[i]]
00547       value = [defaults[i+1]]
00548 
00549       OpenRTM_aist.eraseHeadBlank(key)
00550       OpenRTM_aist.eraseTailBlank(key)
00551 
00552       OpenRTM_aist.eraseHeadBlank(value)
00553       OpenRTM_aist.eraseTailBlank(value)
00554 
00555       self.setDefault(key[0], value[0])
00556 
00557       i +=2
00558 
00559 
00560 
00561   #============================================================
00562   # load and save functions
00563   #============================================================
00564 
00565   ##
00566   # @if jp
00567   #
00568   # @brief 指定された出力ストリームに、プロパティリストを出力する
00569   #
00570   # 指定された出力ストリームに、プロパティリストを出力する。
00571   # このメソッドは主にデバッグに用いられる。
00572   #
00573   # @param self
00574   # @param out 出力ストリーム
00575   #
00576   # @else
00577   #
00578   # @brief Prints this property list out to the specified output stream
00579   #
00580   # Prints this property list out to the specified output stream.
00581   # This method is useful for debugging.
00582   #
00583   # @param out an output stream.
00584   #
00585   # @endif
00586   def list(self, out):
00587     self._store(out, "", self)
00588     return
00589 
00590 
00591   ##
00592   # @if jp
00593   #
00594   # @brief 入力ストリームからキーと要素が対になったプロパティリストを読み込む
00595   #
00596   # 入力ストリームからキーと要素が対になったプロパティリストを読み込む。
00597   # ストリームは、ISO 8859-1 文字エンコーディングを使用しているとみなされる。
00598   # 各プロパティは、入力ストリームに行単位で登録されているものとみなされ、
00599   # 各行は行区切り文字 (\\n、\\r、または \\r\\n) で終わる。
00600   # 入力ストリームから読み込んだ行は、入力ストリームでファイルの終わりに
00601   # 達するまで処理される。
00602   #
00603   # 空白文字だけの行、または最初の非空白文字が ASCII 文字 # または ! である
00604   # 行は無視される。つまり、# または ! はコメント行を示す。
00605   #
00606   # 空白行またはコメント行以外のすべての行は、テーブルに追加されるプロパティ
00607   # を記述する。ただし、行の終わりが \ の場合は、次の行があれば継続行として
00608   # 扱われる (下記を参照)。 キーは、最初の非空白文字から、最初の ASCII 文字
00609   # =、:、または空白文字の直前までの、行内のすべての文字から構成される。
00610   #
00611   # キーの終わりを示す文字は、前に \ を付けることによりキーに含めることも
00612   # できる。キーの後ろの空白はすべてスキップされる。
00613   # キーの後ろの最初の非空白文字が = または : である場合は、これらのキーは
00614   # 無視され、そのあとの空白文字もすべてスキップされる。
00615   # 行内のそれ以外の文字はすべて、関連した要素文字列の一部となる。
00616   # 要素文字列内では、ASCII エスケープシーケンス \\t、\\n、\\r、\\\\、\\"、
00617   # \\'、\\ (円記号とスペース)、および \\uxxxx は認識され、単独の文字に変換
00618   # される。
00619   # また、行の最後の文字が \ である場合は、次の行は現在の行の継続として
00620   # 扱われる。その場合、\ と行区切り文字が破棄され、継続行の先頭に空白が
00621   # あればそれもすべて破棄され、要素文字列の一部にはならない。 
00622   #
00623   # たとえば、次の 4 行はそれぞれキー Truth と関連した要素値 Beauty を表す。
00624   # 
00625   # Truth = Beauty <BR>
00626   # Truth:Beauty <BR>
00627   # Truth\\t\\t\\t:Beauty <BR>
00628   #
00629   # また、次の 3 行は 1 つのプロパティを表す。 
00630   #
00631   # fruits\\t\\t\\t\\tapple, banana, pear, \ <BR>
00632   #                                  cantaloupe, watermelon, \ <BR>
00633   #                                  kiwi, mango <BR>
00634   # キーは fruits で、次の要素に関連付けれられる。 
00635   # "apple, banana, pear, cantaloupe, watermelon, kiwi, mango"
00636   # 最終的な結果でコンマのあとに必ずスペースが表示されるように、
00637   # 各 \ の前にスペースがある。行の終わりを示す \ と、継続行の先頭にある
00638   # 空白は破棄され、他の文字に置換されない。 
00639   # また、次の 3 番目の例では、キーが cheeses で、関連した要素が空の文字列
00640   # であることを表す。 
00641   #
00642   # cheeses <BR>
00643   # キーは、cheeses で、関連要素は空の文字列であることを指定している。 
00644   #
00645   # @param self
00646   # @param inStream 入力ストリーム 
00647   #
00648   # @else
00649   #
00650   # @brief Loads property list consists of key:value from input stream
00651   #
00652   # Reads a property list (key and element pairs) from the input stream.
00653   # The stream is assumed to be using the ISO 8859-1 character encoding; that
00654   # is each byte is one Latin1 character. Characters not in Latin1, and
00655   # certain special characters, can be represented in keys and elements using
00656   # escape sequences similar to those used for character and string literals
00657   # The differences from the character escape sequences used for characters
00658   # and strings are: 
00659   # - Octal escapes are not recognized. 
00660   # - The character sequence \b does not represent a backspace character. 
00661   # - The method does not treat a backslash character, \, before a non-valid
00662   #   escape character as an error; the backslash is silently dropped. For
00663   #   example, in a Java string the sequence "\z" would cause a compile time
00664   #   error. In contrast, this method silently drops the backslash. 
00665   #   Therefore, this method treats the two character sequence "\b" as 
00666   #   equivalent to the single character 'b'. 
00667   # - Escapes are not necessary for single and double quotes; however, by the
00668   #   rule above, single and double quote characters preceded by a backslash
00669   #   still yield single and double quote characters, respectively. 
00670   # An IllegalArgumentException is thrown if a malformed Unicode escape
00671   # appears in the input. 
00672   #
00673   # This method processes input in terms of lines. A natural line of input is
00674   # terminated either by a set of line terminator characters
00675   # (\n or \r or \r\n) or by the end of the file. A natural line may be 
00676   # either a blank line, a comment line, or hold some part of a key-element 
00677   # pair. The logical line holding all the data for a key-element pair may 
00678   # be spread out across several adjacent natural lines by escaping the line 
00679   # terminator sequence with a backslash character, \. Note that a comment 
00680   # line cannot be extended in this manner; every natural line that is a 
00681   # comment must have its own comment indicator, as described below. If a 
00682   # logical line is continued over several natural lines, the continuation 
00683   # lines receive further processing, also described below. Lines are read 
00684   # from the input stream until end of file is reached. 
00685   #
00686   # A natural line that contains only white space characters is considered
00687   # blank and is ignored. A comment line has an ASCII '#' or '!' as its first
00688   # non-white space character; comment lines are also ignored and do not
00689   # encode key-element information. In addition to line terminators, this
00690   # method considers the characters space (' ', '\u0020'), tab 
00691   # ('\t', '\u0009'), and form feed ('\f', '\u000C') to be white space. 
00692   #
00693   # If a logical line is spread across several natural lines, the backslash
00694   # escaping the line terminator sequence, the line terminator sequence, and
00695   # any white space at the start the following line have no affect on the key
00696   # or element values. The remainder of the discussion of key and element
00697   # parsing will assume all the characters constituting the key and element
00698   # appear on a single natural line after line continuation characters have
00699   # been removed. Note that it is not sufficient to only examine the 
00700   # character preceding a line terminator sequence to see if the line 
00701   # terminator is escaped; there must be an odd number of contiguous 
00702   # backslashes for the line terminator to be escaped. Since the input is 
00703   # processed from left to right, a non-zero even number of 2n contiguous 
00704   # backslashes before a line terminator (or elsewhere) encodes n 
00705   # backslashes after escape processing. 
00706   #
00707   # The key contains all of the characters in the line starting with the 
00708   # first non-white space character and up to, but not including, the first
00709   # unescaped '=', ':', or white space character other than a line 
00710   # terminator. All of these key termination characters may be included in 
00711   # the key by escaping them with a preceding backslash character; 
00712   # for example,
00713   #
00714   # \:\=
00715   #
00716   # would be the two-character key ":=". Line terminator characters can be
00717   # included using \r and \n escape sequences. Any white space after the key
00718   # is skipped; if the first non-white space character after the key is '=' 
00719   # or ':', then it is ignored and any white space characters after it are 
00720   # also skipped. All remaining characters on the line become part of the
00721   # associated element string; if there are no remaining characters, the
00722   # element is the empty string "". Once the raw character sequences
00723   # constituting the key and element are identified, escape processing is
00724   # performed as described above. 
00725   #
00726   # As an example, each of the following three lines specifies the key 
00727   # "Truth" and the associated element value "Beauty": 
00728   #
00729   # Truth = Beauty <BR>
00730   #        Truth:Beauty <BR>
00731   # Truth                  :Beauty <BR>
00732   #  As another example, the following three lines specify a single 
00733   # property: 
00734   #
00735   # fruits                           apple, banana, pear, \ <BR>
00736   #                                  cantaloupe, watermelon, \ <BR>
00737   #                                  kiwi, mango <BR>
00738   # The key is "fruits" and the associated element is: 
00739   # "apple, banana, pear, cantaloupe, watermelon, kiwi, mango"Note that a
00740   # space appears before each \ so that a space will appear after each comma
00741   # in the final result; the \, line terminator, and leading white space on
00742   # the continuation line are merely discarded and are not replaced by one or
00743   # more other characters. 
00744   # As a third example, the line: 
00745   #
00746   # cheeses <BR>
00747   # specifies that the key is "cheeses" and the associated element is the
00748   # empty string "".
00749   #
00750   # @param inStream the input stream.
00751   #
00752   # @endif
00753   def load(self, inStream):
00754     pline = ""
00755     for readStr in inStream:
00756       if not readStr:
00757         continue
00758       
00759       tmp = [readStr]
00760       OpenRTM_aist.eraseHeadBlank(tmp)
00761       _str = tmp[0]
00762       
00763       if _str[0] == "#" or _str[0] == "!" or _str[0] == "\n":
00764         continue
00765 
00766       _str = _str.rstrip('\r\n')
00767 
00768       if _str[len(_str)-1] == "\\" and not OpenRTM_aist.isEscaped(_str, len(_str)-1):
00769         #_str = _str[0:len(_str)-1]
00770         tmp = [_str[0:len(_str)-1]]
00771         OpenRTM_aist.eraseTailBlank(tmp)
00772         #pline += _str
00773         pline += tmp[0]
00774         continue
00775       pline += _str
00776       if pline == "":
00777         continue
00778 
00779       key = []
00780       value = []
00781       self.splitKeyValue(pline, key, value)
00782       key[0] = OpenRTM_aist.unescape(key)
00783       OpenRTM_aist.eraseHeadBlank(key)
00784       OpenRTM_aist.eraseTailBlank(key)
00785 
00786       value[0] = OpenRTM_aist.unescape(value)
00787       OpenRTM_aist.eraseHeadBlank(value)
00788       OpenRTM_aist.eraseTailBlank(value)
00789 
00790       self.setProperty(key[0], value[0])
00791       pline = ""
00792 
00793 
00794   ##
00795   # @if jp
00796   #
00797   # @brief プロパティリストを指定されたストリームに保存する
00798   #
00799   # プロパティリストを指定されたストリームに保存する。
00800   # このメソッドは Java Properties との互換性のために定義されている。
00801   # (内部的には store メソッドを利用している。)
00802   #
00803   # @param self
00804   # @param out 出力ストリーム
00805   # @param header プロパティリストの記述 
00806   #
00807   # @else
00808   #
00809   # @brief Save the properties list to the stream
00810   #
00811   # Deprecated. 
00812   #
00813   # @param out The output stream
00814   # @param header A description of the property list
00815   #
00816   # @endif
00817   def save(self, out, header):
00818     self.store(out, header)
00819     return
00820 
00821 
00822   ##
00823   # @if jp
00824   #
00825   # @brief プロパティリストを出力ストリームへ保存する
00826   #
00827   # Properties テーブル内のプロパティリスト (キーと要素のペア) を、load
00828   # メソッドを使って Properties テーブルにロードするのに適切なフォーマットで
00829   # 出力ストリームに書き込む。 
00830   #
00831   # Properties テーブル内のプロパティリスト (キーと要素のペア) を、load
00832   # メソッドを使って Properties テーブルにロードするのに適切なフォーマットで
00833   # 出力ストリームに書き込む。ストリームは、ISO 8859-1 文字
00834   # エンコーディングを使用して書き込まれる。 
00835   # Properties テーブル (存在する場合) のデフォルトテーブルからの
00836   # プロパティは、このメソッドによっては書き込まれない。 
00837   #
00838   # header 引数が null でない場合は、ASCII 文字の #、header の文字列、
00839   # および行区切り文字が最初に出力ストリームに書き込まれます。このため、
00840   # header は識別コメントとして使うことができる。 
00841   #
00842   # 次に、ASCII 文字の #、現在の日時 (Date の toString メソッドによって
00843   # 現在時刻が生成されるのと同様)、および Writer によって生成される行区切り
00844   # からなるコメント行が書き込まれる。 
00845   #
00846   # 続いて、 Properties テーブル内のすべてのエントリが 1 行ずつ書き出される。
00847   # 各エントリのキー文字列、ASCII 文字の=、関連した要素文字列が書き込まれる。
00848   # 要素文字列の各文字は、エスケープシーケンスとして描画する必要があるか
00849   # どうか確認される。ASCII 文字の \、タブ、改行、および復帰はそれぞれ \\\\、
00850   # \\t、\\n、および \\r として書き込まれる。\\u0020 より小さい文字および
00851   # \\u007E より大きい文字は、対応する 16 進値 xxxx を使って \\uxxxx として
00852   # 書き込まれる。埋め込み空白文字でも後書き空白文字でもない先行空白文字は、
00853   # 前に \ を付けて書き込まれる。キーと値の文字 #、!、=、および : は、
00854   # 必ず正しくロードされるように、前にスラッシュを付けて書き込まれる。 
00855   #
00856   # エントリが書き込まれたあとで、出力ストリームがフラッシュされる。
00857   # 出力ストリームはこのメソッドから復帰したあとも開いたままとなる。 
00858   #
00859   # @param self
00860   # @param out 出力ストリーム
00861   # @param header プロパティリストの記述 
00862   #
00863   # @else
00864   #
00865   # @brief Stores property list to the output stream
00866   #
00867   # Writes this property list (key and element pairs) in this Properties 
00868   # table to the output stream in a format suitable for loading into a 
00869   # Properties table using the load method. The stream is written using the 
00870   # ISO 8859-1 character encoding. 
00871   #
00872   # Properties from the defaults table of this Properties table (if any) are
00873   # not written out by this method. 
00874   #
00875   # If the comments argument is not null, then an ASCII # character, the
00876   # comments string, and a line separator are first written to the output
00877   # stream. Thus, the comments can serve as an identifying comment. 
00878   #
00879   # Next, a comment line is always written, consisting of an ASCII #
00880   # character, the current date and time (as if produced by the toString
00881   # method of Date for the current time), and a line separator as generated
00882   # by the Writer. 
00883   #
00884   # Then every entry in this Properties table is written out, one per line.
00885   # For each entry the key string is written, then an ASCII =, then the
00886   # associated element string. Each character of the key and element strings
00887   # is examined to see whether it should be rendered as an escape sequence.
00888   # The ASCII characters \, tab, form feed, newline, and carriage return are
00889   # written as \\, \t, \f \n, and \r, respectively. Characters less than
00890   # \u0020 and characters greater than \u007E are written as \uxxxx for the
00891   # appropriate hexadecimal value xxxx. For the key, all space characters are
00892   # written with a preceding \ character. For the element, leading space
00893   # characters, but not embedded or trailing space characters, are written
00894   # with a preceding \ character. The key and element characters #, !, =, and
00895   # : are written with a preceding backslash to ensure that they are properly
00896   # loaded. 
00897   #
00898   # After the entries have been written, the output stream is flushed. The
00899   # output stream remains open after this method returns. 
00900   #
00901   # @param out an output stream.
00902   # @param header a description of the property list.
00903   #
00904   # @endif
00905   def store(self, out, header):
00906     out.write("#"+header+"\n")
00907     self._store(out, "", self)
00908 
00909 
00910   #============================================================
00911   # other util functions
00912   #============================================================
00913 
00914   ##
00915   # @if jp
00916   #
00917   # @brief プロパティのキーのリストを vector で返す
00918   #
00919   # メインプロパティリストに同じ名前のキーが見つからない場合は、デフォルトの
00920   # プロパティリストにある個別のキーを含む、このプロパティリストにあるすべて
00921   # のキーのリストを返す。 
00922   #
00923   # @param self
00924   #
00925   # @return プロパティリストにあるすべてのキーのリスト。
00926   #         デフォルトのプロパティリストにあるキーを含む
00927   #
00928   # @else
00929   #
00930   # @brief Returns an vector of all the keys in this property
00931   #
00932   # Returns an enumeration of all the keys in this property list, including
00933   # distinct keys in the default property list if a key of the same name has
00934   # not already been found from the main properties list.
00935   #
00936   # @return an vector of all the keys in this property list, including the
00937   #         keys in the default property list.
00938   #
00939   # @endif
00940   def propertyNames(self):
00941     names = []
00942     for leaf in self.leaf:
00943       self._propertyNames(names, leaf.name, leaf)
00944     return names
00945 
00946 
00947   ##
00948   # @if jp
00949   # @brief プロパティの数を取得する
00950   #
00951   # 設定済みのプロパティ数を取得する。
00952   #
00953   # @param self
00954   #
00955   # @return プロパティ数
00956   #
00957   # @else
00958   # @brief Get number of Properties
00959   # @endif
00960   def size(self):
00961     return len(self.propertyNames())
00962 
00963 
00964   ##
00965   # @if jp
00966   # @brief ノードを検索する
00967   # @else
00968   # @brief Find node of properties
00969   # @endif
00970   # Properties* const Properties::findNode(const std::string& key) const
00971   def findNode(self, key):
00972     if not key:
00973       return None
00974 
00975     keys = []
00976     self.split(key, '.', keys)
00977     return self._getNode(keys, 0, self)
00978 
00979 
00980   ##
00981   # @if jp
00982   # @brief ノードを取得する
00983   #
00984   # 指定したキーを持つノードを取得する。
00985   #
00986   # @param self
00987   # @param key 取得対象ノードのキー
00988   #
00989   # @return 対象ノード
00990   #
00991   # @else
00992   # @brief Get node of Properties
00993   # @endif
00994   def getNode(self, key):
00995     if not key:
00996       return self
00997 
00998     leaf = self.findNode(key)
00999     if leaf:
01000       return leaf
01001 
01002     self.createNode(key)
01003     return self.findNode(key)
01004 
01005 
01006   ##
01007   # @if jp
01008   # @brief 新規ノードを生成する
01009   #
01010   # 指定したキーを持つ新規ノードを生成する。
01011   # 既に同一キーを持つノードが登録済みの場合にはエラーを返す。
01012   #
01013   # @param self
01014   # @param key 新規ノードのキー
01015   #
01016   # @return 新規ノード生成結果
01017   #         指定したキーを持つノードが既に存在する場合にはfalse
01018   #
01019   # @else
01020   #
01021   # @endif
01022   def createNode(self, key):
01023     if not key:
01024       return False
01025 
01026     if self.findNode(key):
01027       return False
01028     
01029     self.setProperty(key,"")
01030     return True
01031 
01032 
01033   ##
01034   # @if jp
01035   # @brief ノードを削除する
01036   #
01037   # 指定した名称を持つプロパティを削除する。
01038   # 削除したプロパティを返す。
01039   #
01040   # @param self
01041   # @param leaf_name 削除対象プロパティ名称
01042   #
01043   # @return 削除したプロパティ
01044   #
01045   # @else
01046   # @brief Get node of Properties
01047   # @endif
01048   def removeNode(self, leaf_name):
01049     len_ = len(self.leaf)
01050     for i in range(len_):
01051       idx = (len_ - 1) - i
01052       if self.leaf[idx].name == leaf_name:
01053         prop = self.leaf[idx]
01054         del self.leaf[idx]
01055         return prop
01056     return None
01057 
01058 
01059   ##
01060   # @if jp
01061   # @brief 子ノードにkeyがあるかどうか
01062   #
01063   # 指定したキーを持つ子ノードが存在するかどうか確認する。
01064   # 存在する場合、子ノードを返す。
01065   #
01066   # @param self
01067   # @param key 確認対象のキー
01068   #
01069   # @return 子ノード
01070   #
01071   # @else
01072   # @brief If key exists in the children
01073   # @endif
01074   def hasKey(self, key):
01075     for leaf in self.leaf:
01076       if leaf.name == key:
01077         return leaf
01078 
01079     return None
01080 
01081 
01082   ##
01083   # @if jp
01084   # @brief 子ノードを全て削除する
01085   #
01086   # @param self
01087   #
01088   # @else
01089   # @brief If key exists in the children
01090   # @endif
01091   def clear(self):
01092     len_ = len(self.leaf)
01093     for i in range(len_):
01094       if self.leaf[-1]:
01095         del self.leaf[-1]
01096 
01097     return
01098 
01099 
01100   ##
01101   # @if jp
01102   # @brief Propertyをマージする
01103   #
01104   # 現在のプロパティに設定したプロパティをマージする。
01105   #
01106   # @param self
01107   # @param prop マージするプロパティ
01108   #
01109   # @return プロパティマージ結果
01110   #
01111   # @else
01112   # @brief Merge properties
01113   # @endif
01114   def mergeProperties(self, prop):
01115     keys = prop.propertyNames()
01116 
01117     for i in range(prop.size()):
01118       self.setProperty(keys[i], prop.getProperty(keys[i]))
01119 
01120     return self
01121 
01122 
01123   ##
01124   # @if jp
01125   # @brief 文字列をキーと値のペアに分割する
01126   #
01127   # 与えられた文字列を、設定されたデリミタでキーと値のペアに分割する。
01128   # まず最初に与えられた文字列に':'もしくは'='が含まれるかを検索し、
01129   # どちらかの文字が含まれている場合にはそれをデリミタとして使用する。
01130   # 両方とも含まれていない場合には、' '(スペース)を用いて分割を試みる。
01131   # 全てのデリミタ候補が含まれていない場合には、与えられた文字列をキーとして
01132   # 設定し、値に空の文字列を設定する。
01133   # どのデリミタ候補についてもエスケープされている(直前に'\'が設定されている)
01134   # 場合には、デリミタとして使用しない。
01135   #
01136   # @param self
01137   # @param _str 分割対象文字列
01138   # @param key 分割結果キー
01139   # @param value 分割結果値
01140   #
01141   # @else
01142   #
01143   # @endif
01144   def splitKeyValue(self, _str, key, value):
01145     i = 0
01146     length = len(_str)
01147 
01148     while i < length:
01149       if (_str[i] == ":" or _str[i] == "=") and not OpenRTM_aist.isEscaped(_str, i):
01150         key.append(_str[0:i])
01151         value.append(_str[i+1:])
01152         return
01153       i += 1
01154 
01155     # If no ':' or '=' exist, ' ' would be delimiter.
01156     i = 0
01157     while i < length:
01158       if (_str[i] == " ") and not OpenRTM_aist.isEscaped(_str, i):
01159         key.append(_str[0:i])
01160         value.append(_str[i+1:])
01161         return
01162       i += 1
01163 
01164     key.append(_str)
01165     value.append("")
01166     return
01167 
01168 
01169   ##
01170   # @if jp
01171   # @brief 文字列を分割する
01172   #
01173   # 与えられた文字列を、与えられたデリミタで分割する。
01174   # 与えられた文字列が空の場合は、エラーを返す。
01175   # 与えられたデリミタがエスケープされている(直前に'\'が設定されている)場合
01176   # には、デリミタとして使用しない。
01177   #
01178   # @param self
01179   # @param _str 分割対象文字列
01180   # @param delim デリミタ
01181   # @param value 分割結果値リスト
01182   #
01183   # @return 分割処理結果
01184   #
01185   # @else
01186   #
01187   # @endif
01188   def split(self, _str, delim, value):
01189     if _str == "":
01190       return False
01191 
01192     begin_it = end_it = 0
01193 
01194     length = len(_str)
01195 
01196     while end_it < length:
01197       if _str[end_it] == delim and not OpenRTM_aist.isEscaped(_str, end_it):
01198         value.append(_str[begin_it:end_it])
01199         begin_it = end_it + 1
01200       end_it += 1
01201 
01202     value.append(_str[begin_it:end_it])
01203     return True
01204 
01205 
01206   ##
01207   # @if jp
01208   # @brief プロパティを取得する
01209   #
01210   # キーリストで指定されたプロパティを取得する。
01211   # キーリストでは、指定するキーのプロパティでの階層関係をリスト形式で表現
01212   # する。
01213   # 指定したキーリストに該当するプロパティが存在しない場合はNoneを返す。
01214   #
01215   # @param self
01216   # @param keys 取得対象プロパティのキーのリスト表現
01217   # @param index キーリストの階層数
01218   # @param curr 検索対象プロパティ
01219   #
01220   # @return 検索対象プロパティ
01221   #
01222   # @else
01223   #
01224   # @endif
01225   def _getNode(self, keys, index, curr):
01226     next = curr.hasKey(keys[index])
01227     if next is None:
01228       return None
01229 
01230     if index < (len(keys) - 1):
01231       index+=1
01232       return next._getNode(keys, index, next)
01233     else:
01234       return next
01235 
01236     return None
01237 
01238 
01239   ##
01240   # @if jp
01241   # @brief プロパティの名称リストを取得する
01242   #
01243   # プロパティの名称を'.'区切りで表現したリストを取得する。
01244   #
01245   # @param self
01246   # @param names プロパティの名称リスト
01247   # @param curr_name 現在のプロパティ名
01248   # @param curr 対象プロパティ
01249   #
01250   # @else
01251   #
01252   # @endif
01253   def _propertyNames(self, names, curr_name, curr):
01254     if len(curr.leaf) > 0:
01255       for i in range(len(curr.leaf)):
01256         next_name = curr_name+"."+curr.leaf[i].name
01257         self._propertyNames(names, next_name, curr.leaf[i])
01258     else:
01259       names.append(curr_name)
01260 
01261     return
01262 
01263 
01264   ##
01265   # @if jp
01266   # @brief プロパティの名称リストを保存する
01267   #
01268   # プロパティの名称を'.'区切りで表現したリストを保存する。
01269   #
01270   # @param self
01271   # @param out プロパティの名称リスト保存先の出力ストリーム
01272   # @param curr_name 現在のプロパティ名
01273   # @param curr 対象プロパティ
01274   #
01275   # @else
01276   #
01277   # @endif
01278   def _store(self, out, curr_name, curr):
01279     if len(curr.leaf) > 0:
01280       for i in range(len(curr.leaf)):
01281         if curr_name == "":
01282           next_name = curr.leaf[i].name
01283         else:
01284           next_name = curr_name+"."+curr.leaf[i].name
01285         self._store(out, next_name, curr.leaf[i])
01286         
01287     else:
01288       val = curr.value
01289       if val == "":
01290         val = curr.default_value
01291       out.write(curr_name+": "+val+"\n")
01292 
01293     return
01294 
01295 
01296   ##
01297   # @if jp
01298   # @brief インデントを生成する
01299   #
01300   # 指定された数字に従って生成したインデントを返す。
01301   # 返されるインデントは、指定数字×2つの空白。
01302   #
01303   # @param self
01304   # @param index インデント数の指定
01305   #
01306   # @return 生成されたインデント
01307   #
01308   # @else
01309   #
01310   # @endif
01311   def indent(self, index):
01312     space = ""
01313 
01314     for i in range(index-1):
01315       space += "  "
01316 
01317     return space
01318 
01319 
01320   ##
01321   # @if jp
01322   # @brief プロパティの内容を保存する
01323   #
01324   # プロパティに設定された内容を保存する。
01325   # 保存時にはプロパティ階層の深さを表す数字が付加される。
01326   # 値が設定されていないプロパティについては、デフォルト値が出力される。
01327   #
01328   # @param self
01329   # @param out プロパティ内容保存先の出力ストリーム
01330   # @param curr 対象プロパティ
01331   # @param index 現在のプロパティ階層
01332   #
01333   # @else
01334   #
01335   # @endif
01336   def _dump(self, out, curr, index):
01337     if index != 0:
01338       #ut.write(self.indent(index)+"- "+curr.name)
01339       out[0]+=self.indent(index)+"- "+curr.name
01340 
01341     if curr.leaf == []:
01342       if curr.value == "":
01343         #out.write(": "+curr.default_value+"\n")
01344         out[0]+=": "+curr.default_value+"\n"
01345       else:
01346         #out.write(": "+curr.value+"\n")
01347         out[0]+=": "+str(curr.value)+"\n"
01348       return out[0]
01349 
01350     if index != 0:
01351       #out.write("\n")
01352       out[0]+="\n"
01353 
01354     for i in range(len(curr.leaf)):
01355       self._dump(out, curr.leaf[i], index + 1)
01356 
01357     return out[0]
01358 
01359 
01360   ##
01361   # @if jp
01362   # @brief プロパティの内容を出力する
01363   #
01364   # プロパティに設定された内容を出力する。<br>
01365   # friend std::ostream& operator<<(std::ostream& lhs, const Properties& rhs);
01366   # の代わりに、print objにて呼び出し可能とするためのメソッド。
01367   #
01368   # @param self
01369   #
01370   # @return 設定プロパティ文字列表示
01371   #
01372   # @else
01373   #
01374   # @endif
01375   def __str__(self): 
01376     string=[""]
01377     return self._dump(string, self, 0)
01378 
01379   


openrtm_aist_python
Author(s): Shinji Kurihara
autogenerated on Thu Aug 27 2015 14:17:28