Access ElementTree Node Node Node
-
24-09-2019 - |
سؤال
أنا أستخدم وحدة Python ElementTree المصممة. من السهل الوصول إلى الأطفال ، ولكن ماذا عن العقد الوالد أو الأخوة؟ - هل يمكن القيام بذلك بكفاءة دون عبور الشجرة بأكملها؟
المحلول
لا يوجد دعم مباشر في شكل أ parent
السمة ، ولكن ربما يمكنك استخدام الأنماط الموصوفة هنا لتحقيق التأثير المطلوب. يتم اقتراح خط واحد التالي (من المنشور المرتبط) لإنشاء رسم خرائط من الطفل إلى الوالد لشجرة كاملة:
parent_map = dict((c, p) for p in tree.getiterator() for c in p)
نصائح أخرى
إجابة فيناي يجب أن لا يزال يعمل ، ولكن من أجل Python 2.7+ و 3.2+ يوصى بما يلي:
parent_map = {c:p for p in tree.iter() for c in p}
getiterator()
تم إهماله لصالح iter()
, ، ومن الجيد استخدام الجديد dict
قائمة مُنشئ الفهم.
ثانياً ، أثناء إنشاء مستند XML ، من الممكن أن يكون لدى الطفل العديد من الآباء ، على الرغم من أن هذا يتم إزالته بمجرد إجراء تسلسل المستند. إذا كان ذلك مهمًا ، فقد تجرب هذا:
parent_map = {}
for p in tree.iter():
for c in p:
if c in parent_map:
parent_map[c].append(p)
# Or raise, if you don't want to allow this.
else:
parent_map[c] = [p]
# Or parent_map[c] = p if you don't want to allow this
يمكنك استخدام XPath ...
تدوين في ElementTree.
<parent>
<child id="123">data1</child>
</parent>
xml.findall('.//child[@id="123"]...')
>> [<Element 'parent'>]
كما ذكر في احصل على عنصر الأصل بعد استخدام طريقة البحث (xml.etree.elementtree) سيكون عليك إجراء بحث غير مباشر عن الوالدين. وجود XML:
<a>
<b>
<c>data</c>
<d>data</d>
</b>
</a>
على افتراض أنك قمت بإنشاء عنصر etree في xml
متغير ، يمكنك استخدام:
In[1] parent = xml.find('.//c/..')
In[2] child = parent.find('./c')
مما أدى إلى:
Out[1]: <Element 'b' at 0x00XXXXXX>
Out[2]: <Element 'c' at 0x00XXXXXX>
يمكن العثور على الوالدين العالي على النحو التالي:secondparent=xml.find('.//c/../..')
مستخدم <Element 'a' at 0x00XXXXXX>
لا يمكن استخدام محدد XPath '..' لاسترداد العقدة الأصل في 3.5.3 ولا 3.6.1 (على الأقل على OSX) ، على سبيل المثال في الوضع التفاعلي:
import xml.etree.ElementTree as ET
root = ET.fromstring('<parent><child></child></parent>')
child = root.find('child')
parent = child.find('..') # retrieve the parent
parent is None # unexpected answer True
الجواب الأخير يكسر كل الآمال ...
طريقة أخرى إذا كانت تريد فقط الوالد الفرعي الواحد وأيضًا معروفة XPath's Subelement.
parentElement = subElement.find(xpath+"/..")
إذا كنت تستخدم LXML ، تمكنت من الحصول على العنصر الأصل بما يلي:
parent_node = next(child_node.iterancestors())
هذا سوف يرفع StopIteration
استثناء إذا كان العنصر لا يحتوي على أسلاف - لذا كن مستعدًا للقبض على أنه إذا كنت قد تصادف هذا السيناريو.
لصق هنا إجابتي https://stackoverflow.com/a/54943960/492336:
واجهت مشكلة مماثلة وحصلت على خلاقة بعض الشيء. تبين أن لا شيء يمنعنا من إضافة معلومات النسب لأنفسنا. يمكننا لاحقًا تجريده بمجرد أن لا نحتاج إليه.
def addParentInfo(et):
for child in et:
child.attrib['__my_parent__'] = et
addParentInfo(child)
def stripParentInfo(et):
for child in et:
child.attrib.pop('__my_parent__', 'None')
stripParentInfo(child)
def getParent(et):
if '__my_parent__' in et.attrib:
return et.attrib['__my_parent__']
else:
return None
# Example usage
tree = ...
addParentInfo(tree.getroot())
el = tree.findall(...)[0]
parent = getParent(el)
while parent:
doSomethingWith(parent)
parent = getParent(parent)
stripParentInfo(tree.getroot())
انظر إلى 19.7.2.2. الجزء: بناء جملة XPath ...
ابحث عن والد العقدة باستخدام المسار:
parent_node = node.find('..')