0

私は、XMLファイルとして保存された非常に大きな構成ファイル内のレコードへのフルパスを検索して提示するPythonユーティリティに取り組んでいます。ファイル サイズは 12M で、294460 行を保持でき、さらに大きなサイズに拡張できます。

ここに例があります(簡略化):

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<root version="1.1.1">
  <record path="">
    <record path="path1">
      <field name="some_name1" value="1234"/>
      <record path="path2">
        <field name="0" value="abcd0"/>
        <field name="1" value="abcd1"/>
        <field name="2" value="abcd2"/>
        <field name="28" value="abcd28"/>
        <field name="29" value="abcd29"/>
      </record>
    </record>
    <record path="pathx">
      <record path="pathy">
        <record path="pathz">
        </record>
        <record path="pathv">
          <record path="pathw">
            <field name="some_name1" value="yes"/>
            <field name="some_name2" value="2084"/>
            <field name="some_buffer_name" value="14"/>
            <record path="cache_value">
              <field name="some_name7000" value="12"/>
            </record>
    </record>
        <record path="path_something">
          <field name="key_word1" value="8"/>
          <field name="key_word2" value="9"/>
          <field name="key_word3" value="10"/>
          <field name="key5" value="1"/>
          <field name="key6" value="1"/>
          <field name="key7" value="yes"/>
    </record>
  </record>
</root>

ファイルで実行して、ノードのパスまたはフィールド属性に検索文字列を保持するすべてのノードをファイルすることに興味があります。ノードの「タイプ」(またはノード名) は、レコードまたはフィールドのいずれかである可能性があるため、属性の名前はパスから名前に変わる可能性があります。

minidom を使用して xml を解析および検索しましたが、私のコードはリソースと時間がかかりすぎています。

これは私が書いたものです: xml_file_location はファイルの場所です string_to_search は XML ファイル内で検索する文字列であり、見つかったノードへのパスは type: record のノードに保存され、名前は: path という属性です。 、これは私がユーザーに出力するものです。

with open(xml_file_location, 'r') as inF:
# search the xml file for lines with the string for search
    for line in inF:
        if string_to_search in line:
            found_counter = found_counter + 1
            node_type = line.strip(" ").split(" ")[0]
            node_type = re.sub('[^A-Za-z0-9]+', '', node_type)
            node_attr = line.strip(" ").split(" ")[1]
            node_value = re.sub('[^A-Za-z0-9_]+', '', node_attr.split("=")[1])
            node_attr = re.sub('[^A-Za-z0-9]+', '', node_attr.split("=")[0])
            #print node_type
            #print node_attr
            #print node_value
            if node_type in lines_dict:
                if not node_attr in lines_dict[node_type]:
                    lines_dict[node_type][node_attr] = [nome_value]
                elif not node_value in lines_dict[node_type][node_attr]:
                        lines_dict[node_type][node_attr].append(node_value)
            else:
                lines_dict[node_type] = {}
                lines_dict[node_type][node_attr] = [node_value]

print "Found: %s strings in the xml file" %found_counter

#pp = pprint.PrettyPrinter(indent=4)
#pp.pprint(lines_dict)

print "Parsing the xml file"
dom = parse(xml_file_location)

print "Locating the full path"

for node_type in lines_dict:
# for all types of node
    elements = dom.getElementsByTagName(node_type)
    # create the elements for those nodes
    for node in elements:
    # go over all nodes in the elements
        if node.hasAttribute(node_attr):
            if node.getAttribute(node_attr) in lines_dict[node_type][node_attr]:
            # check if the attribute appears in the lines dict 
                result = node.getAttribute(node_attr) # holds the path
                parent = node.parentNode       # create a pointer to point on the parent node
                while parent.getAttribute("path") != "":
                # while didn't reach the root of the conf - a record that has an empty path attribute
                    result = parent.getAttribute("path") + "." + result     # add the path of the parent to the full path
                    parent = parent.parentNode                              # advance the parent pointer
                print
                print "Found: %s" %node.toprettyxml().split("\n")[0]
                print "Path:  %s" %result

例: 次を検索します: abcd1 ユーティリティはフル パスを出力します: path1.path2 または、次を検索します: pathw ユーティリティは次を返します: pathx.pathy.pathv

非常に非効率的であることは理解しています。構成内のすべてのノードを調べて、単純な文字列検索で list_dic に入れたものと比較します。

外部モジュールを使用してそれを実行しようとしましたが、成功しませんでした

この種の検索を行うためのより効率的な方法を探しています。その助けにとても感謝しています。

4

2 に答える 2

2

@Martijn Pieters が言ったように、Python 2.5 以降の stdlib にある ElementTree を使用します。「with」を使用しているため、2.6 以降を使用していると想定します。習得は簡単で、そのメンタル モデルは DOM に非常に近いものです。

昔ながらの代替手段は SAX 解析です。これは、ずっと前から stdlib にモジュールがありました。基本的には、パーサーが開始タグまたは終了タグに遭遇するたびに実行するコールバックを指定します。これは少し不自然ですが (XML 論理構造ではなく、テキスト処理の観点から考える必要があります)、非常に効率的です。

于 2013-09-17T08:06:15.970 に答える