python - لغة - طباعة جميلة XML في بيثون




كود بايثون (12)

ما هي أفضل طريقة (أو حتى الطرق المختلفة) لطباعة xml في Python؟


lxml حديث ، محدث ، ويتضمن وظيفة طباعة جميلة

import lxml.etree as etree

x = etree.parse("filename")
print etree.tostring(x, pretty_print=True)

تحقق من البرنامج التعليمي lxml: http://lxml.de/tutorial.html


إذا كان لديك xmllint يمكنك إنتاج عملية فرعية واستخدامها. xmllint --format <file> تطبع جميلة XML الإدخال الخاص بها إلى الإخراج القياسي.

لاحظ أن هذه الطريقة تستخدم برنامجًا خارجيًا لـ python ، مما يجعله نوعًا من الاختراق.

def pretty_print_xml(xml):
    proc = subprocess.Popen(
        ['xmllint', '--format', '/dev/stdin'],
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
    )
    (output, error_output) = proc.communicate(xml);
    return output

print(pretty_print_xml(data))

إلقاء نظرة على وحدة vkbeautify .

إنه نسخة python من البرنامج المساعد javascript / nodejs بشعبية كبيرة بنفس الاسم. يمكنها طباعة / تصغير XML ، JSON ونص CSS. يمكن أن يكون الإدخال والإخراج سلسلة / ملف في أي مجموعات. إنه مضغوط جدا وليس لديه أي تبعية.

أمثلة :

import vkbeautify as vkb

vkb.xml(text)                       
vkb.xml(text, 'path/to/dest/file')  
vkb.xml('path/to/src/file')        
vkb.xml('path/to/src/file', 'path/to/dest/file') 

الحل الآخر هو استعارة هذه الوظيفة indent ، لاستخدامها مع مكتبة ElementTree المبنية في Python منذ 2.5. إليك ما سيبدو عليه:

from xml.etree import ElementTree

def indent(elem, level=0):
    i = "\n" + level*"  "
    j = "\n" + (level-1)*"  "
    if len(elem):
        if not elem.text or not elem.text.strip():
            elem.text = i + "  "
        if not elem.tail or not elem.tail.strip():
            elem.tail = i
        for subelem in elem:
            indent(subelem, level+1)
        if not elem.tail or not elem.tail.strip():
            elem.tail = j
    else:
        if level and (not elem.tail or not elem.tail.strip()):
            elem.tail = j
    return elem        

root = ElementTree.parse('/tmp/xmlfile').getroot()
indent(root)
ElementTree.dump(root)

حاولت تعديل الإجابة "ade" أعلاه ، ولكن لن يسمح لي بالتحرير بعد أن قدمت تعليقات في البداية بشكل مجهول. هذا هو نسخة أقل عربات التي تجرها الدواب من وظيفة لطباعة ElementTree جميلة.

def indent(elem, level=0, more_sibs=False):
    i = "\n"
    if level:
        i += (level-1) * '  '
    num_kids = len(elem)
    if num_kids:
        if not elem.text or not elem.text.strip():
            elem.text = i + "  "
            if level:
                elem.text += '  '
        count = 0
        for kid in elem:
            indent(kid, level+1, count < num_kids - 1)
            count += 1
        if not elem.tail or not elem.tail.strip():
            elem.tail = i
            if more_sibs:
                elem.tail += '  '
    else:
        if level and (not elem.tail or not elem.tail.strip()):
            elem.tail = i
            if more_sibs:
                elem.tail += '  '

كان لي بعض المشاكل مع الطباعة minidom جميلة. سأحصل على UnicodeError كلما حاولت طباعة وثيقة بأحرف خارج الترميز المعين ، على سبيل المثال إذا كان لدي β في وثيقة وحاولت doc.toprettyxml(encoding='latin-1') . ها هو حل عملي لذلك:

def toprettyxml(doc, encoding):
    """Return a pretty-printed XML document in a given encoding."""
    unistr = doc.toprettyxml().replace(u'<?xml version="1.0" ?>',
                          u'<?xml version="1.0" encoding="%s"?>' % encoding)
    return unistr.encode(encoding, 'xmlcharrefreplace')

كما أشار آخرون ، فإن طابعة lxml بها طابعة جميلة.

كن على علم على الرغم من أنه بشكل افتراضي يغير أقسام CDATA إلى النص العادي ، والذي يمكن أن يكون له نتائج سيئة.

إليك وظيفة بايثون تحافظ على ملف الإدخال وتغير فقط المسافة البادئة (لاحظ strip_cdata=False ). علاوة على ذلك ، فإنه يتأكد من أن الإخراج يستخدم UTF-8 كتشفير بدلاً من ASCII الافتراضي (لاحظ encoding='utf-8' ):

from lxml import etree

def prettyPrintXml(xmlFilePathToPrettyPrint):
    assert xmlFilePathToPrettyPrint is not None
    parser = etree.XMLParser(resolve_entities=False, strip_cdata=False)
    document = etree.parse(xmlFilePathToPrettyPrint, parser)
    document.write(xmlFilePathToPrettyPrint, pretty_print=True, encoding='utf-8')

استخدام المثال:

prettyPrintXml('some_folder/some_file.xml')

لدى BeautifulSoup وظيفة prettify() سهلة الاستخدام.

إنه مسافة بادئة مسافة واحدة لكل مستوى بادئة. وهو يعمل أفضل بكثير من جميلة في lxml و قصيرة وحلوة.

from bs4 import BeautifulSoup

bs = BeautifulSoup(open(xml_file), 'xml')
print bs.prettify()

لقد واجهت هذه المشكلة وحلت على هذا النحو:

def write_xml_file (self, file, xml_root_element, xml_declaration=False, pretty_print=False, encoding='unicode', indent='\t'):
    pretty_printed_xml = etree.tostring(xml_root_element, xml_declaration=xml_declaration, pretty_print=pretty_print, encoding=encoding)
    if pretty_print: pretty_printed_xml = pretty_printed_xml.replace('  ', indent)
    file.write(pretty_printed_xml)

في هذه التعليمة البرمجية يتم استدعاء هذه الطريقة على النحو التالي:

try:
    with open(file_path, 'w') as file:
        file.write('<?xml version="1.0" encoding="utf-8" ?>')

        # create some xml content using etree ...

        xml_parser = XMLParser()
        xml_parser.write_xml_file(file, xml_root, xml_declaration=False, pretty_print=True, encoding='unicode', indent='\t')

except IOError:
    print("Error while writing in log file!")

هذا يعمل فقط لأن etree بشكل افتراضي يستخدم مسافة two spaces المسافة البادئة ، والتي لا أجد الكثير من التركيز على المسافة البادئة وبالتالي ليست جميلة. لم أتمكن من وضع أي إعداد لـ etree أو parameter لأي وظيفة لتغيير المسافة البادئة القياسية. أنا أحب مدى سهولة استخدام etree ، ولكن هذا كان مزعجًا حقًا.


وهنا حل بلدي (hacky؟) للالتفاف على مشكلة عقدة النص القبيح.

uglyXml = doc.toprettyxml(indent='  ')

text_re = re.compile('>\n\s+([^<>\s].*?)\n\s+</', re.DOTALL)    
prettyXml = text_re.sub('>\g<1></', uglyXml)

print prettyXml

سوف ينتج الرمز أعلاه:

<?xml version="1.0" ?>
<issues>
  <issue>
    <id>1</id>
    <title>Add Visual Studio 2005 and 2008 solution files</title>
    <details>We need Visual Studio 2005/2008 project files for Windows.</details>
  </issue>
</issues>

بدلا من هذا:

<?xml version="1.0" ?>
<issues>
  <issue>
    <id>
      1
    </id>
    <title>
      Add Visual Studio 2005 and 2008 solution files
    </title>
    <details>
      We need Visual Studio 2005/2008 project files for Windows.
    </details>
  </issue>
</issues>

إخلاء المسؤولية: ربما تكون هناك بعض القيود.



from yattag import indent

pretty_string = indent(ugly_string)

لن تضيف مسافات أو خطوطًا جديدة داخل العقد النصية ، إلا إذا طلبت ذلك مع:

indent(mystring, indent_text = True)

يمكنك تحديد ما يجب أن تكون عليه وحدة المسافة البادئة وما ينبغي أن يكون عليه السطر الجديد.

pretty_xml_string = indent(
    ugly_xml_string,
    indentation = '    ',
    newline = '\r\n'
)

المستند موجود على http://www.yattag.org الصفحة الرئيسية.





pretty-print