Это одно из мест, с помощью которого привязка данных, используемая во многих новых фреймворках JavaScript, будет очень полезна для вас ...
Итак, если вы используете Angular, React или любые другие фреймворки, которые делают два способа связывания данных, эта проблема просто исправлена для вас, поэтому простым языком ваш результат undefined
на первом этапе, поэтому вы получили result = undefined
до получения данных, а затем, как только вы получите результат , он будет обновляться и присваиваться новому значению, которое отвечает на ваш вызов Ajax ...
Но как вы можете сделать это в чистом javascript или jQuery, например, как вы задали этот вопрос?
Вы можете использовать обратный вызов, обещание и недавно наблюдаемое, чтобы обрабатывать его для вас, например, в обещаниях мы имеем некоторые функции, такие как success () или then (), которые будут выполняться, когда ваши данные будут готовы для вас, с функцией обратного вызова или подписки на наблюдаемые.
Например, в вашем случае, в котором вы используете jQuery, вы можете сделать что-то вроде этого:
$(document).ready(function(){
function foo() {
$.ajax({url: "api/data", success: function(data){
fooDone(data); //after we have data, we pass it to fooDone
}});
};
function fooDone(data) {
console.log(data); //fooDone has the data and console.log it
};
foo(); //call happens here
});
Для получения дополнительной информации n изучение обещаний и наблюдаемых, которые являются новыми способами для создания асинхронных материалов.
Я предлагаю ElementTree
. Существуют и другие совместимые реализации одного и того же API, такие как lxml
и cElementTree
в самой стандартной библиотеке Python; но в этом контексте то, что они в основном добавляют, еще быстрее - легкость программирования зависит от API, который определяет ElementTree
.
После создания экземпляра элемента e
из XML , например с функцией XML или путем разбора файла с чем-то вроде
import xml.etree.ElementTree
e = xml.etree.ElementTree.parse('thefile.xml').getroot()
или любого из многих других способов, показанных в ElementTree
, вы просто делаете что-то вроде:
for atype in e.findall('type'):
print(atype.get('foobar'))
и подобных, обычно довольно простых, шаблонов кода.
Я довольно легко понимаю Python xml.dom и xml.dom.minidom . Имейте в виду, что DOM не подходит для больших объемов XML, но если ваш вход довольно мал, это будет работать нормально.
Я мог бы предложить declxml .
Полное раскрытие: я написал эту библиотеку, потому что я искал способ преобразования между структурами данных XML и Python без необходимости писать десятки строки императивного кода синтаксического анализа / сериализации с ElementTree.
С помощью declxml вы используете процессоры для декларативного определения структуры вашего XML-документа и того, как сопоставить структуру данных XML и Python. Процессоры используются как для сериализации, так и для синтаксического анализа, а также для базового уровня валидации.
Анализ в структурах данных Python прост:
import declxml as xml
xml_string = """
<foo>
<bar>
<type foobar="1"/>
<type foobar="2"/>
</bar>
</foo>
"""
processor = xml.dictionary('foo', [
xml.dictionary('bar', [
xml.array(xml.integer('type', attribute='foobar'))
])
])
xml.parse_from_string(processor, xml_string)
Что дает результат:
{'bar': {'foobar': [1, 2]}}
Вы также можете использовать один и тот же процессор для сериализации данных в XML
data = {'bar': {
'foobar': [7, 3, 21, 16, 11]
}}
xml.serialize_to_string(processor, data, indent=' ')
, который производит следующий вывод
<?xml version="1.0" ?>
<foo>
<bar>
<type foobar="7"/>
<type foobar="3"/>
<type foobar="21"/>
<type foobar="16"/>
<type foobar="11"/>
</bar>
</foo>
Если вы хотите работа с объектами вместо словарей, вы можете определить процессоры для преобразования данных в объекты и из них.
import declxml as xml
class Bar:
def __init__(self):
self.foobars = []
def __repr__(self):
return 'Bar(foobars={})'.format(self.foobars)
xml_string = """
<foo>
<bar>
<type foobar="1"/>
<type foobar="2"/>
</bar>
</foo>
"""
processor = xml.dictionary('foo', [
xml.user_object('bar', Bar, [
xml.array(xml.integer('type', attribute='foobar'), alias='foobars')
])
])
xml.parse_from_string(processor, xml_string)
Что производит следующий вывод
{'bar': Bar(foobars=[1, 2])}
Здесь очень простой, но эффективный код с использованием cElementTree
.
try:
import cElementTree as ET
except ImportError:
try:
# Python 2.5 need to import a different module
import xml.etree.cElementTree as ET
except ImportError:
exit_err("Failed to import cElementTree from any known place")
def find_in_tree(tree, node):
found = tree.find(node)
if found == None:
print "No %s in file" % node
found = []
return found
# Parse a xml file (specify the path)
def_file = "xml_file_name.xml"
try:
dom = ET.parse(open(def_file, "r"))
root = dom.getroot()
except:
exit_err("Unable to open and parse input definition file: " + def_file)
# Parse to find the child nodes list of node 'myNode'
fwdefs = find_in_tree(root,"myNode")
Источник:
http://www.snip2code.com/Snippet/991/python-xml-parse?fromPage=1
Чтобы добавить еще одну возможность, вы можете использовать untangle , так как это простая библиотека объектов xml-to-python. Здесь у вас есть пример:
Установка
pip install untangle
Использование
Ваш xml-файл (немного изменился):
<foo>
<bar name="bar_name">
<type foobar="1"/>
</bar>
</foo>
, доступ к атрибутам с помощью unangle :
import untangle
obj = untangle.parse('/path_to_xml_file/file.xml')
print obj.foo.bar['name']
print obj.foo.bar.type['foobar']
, выход будет:
bar_name
1
Более подробную информацию о распутывании можно найти здесь . Также (если вам интересно), вы можете найти список инструментов для работы с XML и Python здесь (вы также увидите, что наиболее распространенные из них были упомянуты в предыдущих ответах ).
lxml.objectify действительно прост.
Принимая ваш образец текста:
from lxml import objectify
from collections import defaultdict
count = defaultdict(int)
root = objectify.fromstring(text)
for item in root.bar.type:
count[item.attrib.get("foobar")] += 1
print dict(count)
Выход:
{'1': 1, '2': 1}
import xml.etree.ElementTree as ET
data = '''<foo>
<bar>
<type foobar="1"/>
<type foobar="2"/>
</bar>
</foo>'''
tree = ET.fromstring(data)
lst = tree.findall('bar/type')
for item in lst:
print item.get('foobar')
Это будет печатать значение атрибута foobar.
Есть много вариантов. cElementTree выглядит превосходно, если проблема связана с скоростью и памятью. Это очень мало накладных расходов по сравнению с простое чтение в файле с помощью readlines
.
Соответствующие показатели можно найти в приведенной ниже таблице, скопированной с веб-сайта cElementTree :
library time space
xml.dom.minidom (Python 2.1) 6.3 s 80000K
gnosis.objectify 2.0 s 22000k
xml.dom.minidom (Python 2.4) 1.4 s 53000k
ElementTree 1.2 1.6 s 14500k
ElementTree 1.2.4/1.3 1.1 s 14500k
cDomlette (C extension) 0.540 s 20500k
PyRXPU (C extension) 0.175 s 10850k
libxml2 (C extension) 0.098 s 16000k
readlines (read as utf-8) 0.093 s 8850k
cElementTree (C extension) --> 0.047 s 4900K <--
readlines (read as ascii) 0.032 s 5050k
Как указано @jfs , cElementTree
поставляется в комплекте с Python:
from xml.etree import cElementTree as ElementTree
. from xml.etree import ElementTree
(ускоренная версия C используется автоматически). Python имеет интерфейс для синтаксического анализатора expat.
xml.parsers.expat
Это не проверяющий парсер, поэтому плохой xml не будет пойман. Но если вы знаете, что ваш файл правильный, то это очень хорошо, и вы, вероятно, получите точную информацию, которую хотите, и вы можете отбросить остальное на лету.
stringofxml = """<foo>
<bar>
<type arg="value" />
<type arg="value" />
<type arg="value" />
</bar>
<bar>
<type arg="value" />
</bar>
</foo>"""
count = 0
def start(name, attr):
global count
if name == 'type':
count += 1
p = expat.ParserCreate()
p.StartElementHandler = start
p.Parse(stringofxml)
print count # prints 4
Вы можете использовать BeautifulSoup
from bs4 import BeautifulSoup
x="""<foo>
<bar>
<type foobar="1"/>
<type foobar="2"/>
</bar>
</foo>"""
y=BeautifulSoup(x)
>>> y.foo.bar.type["foobar"]
u'1'
>>> y.foo.bar.findAll("type")
[<type foobar="1"></type>, <type foobar="2"></type>]
>>> y.foo.bar.findAll("type")[0]["foobar"]
u'1'
>>> y.foo.bar.findAll("type")[1]["foobar"]
u'2'