3

My goal is to build an xml template with placeholders for variable attributes. for some reasons, the template would not take in new data into its placeholders.

Here's an example:

x=2*5
xmlTemplate="""
<personal reference="500.txt">
    <others:sequence>
        <feature:name="name" age="age" dob="dob"/>
    </others:sequence>
</personal>""".format(name='Michael', age=x, dob=15/10/1900)
print xmlTemplate

Output:

<personal reference="500.txt">
    <others:sequence>
        <feature:name="name" age="age" dob="dob"/>
    </others:sequence>
</personal>

Ideal output:

<personal reference="500.txt">
    <others:sequence>
        <feature:name="Michael" age="10" dob="15/10/1900"/>
    </others:sequence>
</personal>

Any ideas? Thanks.

Tiger1
  • 1,327
  • 5
  • 19
  • 40

2 Answers2

4

To create an XML document in Python, it seems easier to use the Yattag library.

from yattag import Doc

doc, tag, text = Doc().tagtext()

x = 2*5

with tag('personal', reference = "500.txt"):
    with tag('others:sequence'):
        doc.stag('feature', name = "Michael", age = str(x), dob = "15/10/1900")

print(doc.getvalue())

When run, the above code will generate the following XML:

<personal reference="500.txt">
  <others:sequence>
    <feature name="Michael" age="10" dob="15/10/1900" />
  </others:sequence>
</personal>

Note: Indentation was added to the example above for readability, as getvalue returns a single line without spaces between tags. To produce a formatted document, use the indent function.

Stevoisiak
  • 23,794
  • 27
  • 122
  • 225
John Smith Optional
  • 22,259
  • 12
  • 43
  • 61
3

Your template needs curly braces:

x=2*5
xmlTemplate="""
<personal reference="500.txt">
    <others:sequence>
        <feature:name="{name}" age="{age}" dob="{dob}"/>
    </others:sequence>
</personal>""".format(name='Michael', age=x, dob='15/10/1900')
print xmlTemplate

yields

<personal reference="500.txt">
    <others:sequence>
        <feature:name="Michael" age="10" dob="15/10/1900"/>
    </others:sequence>
</personal>

The format method replaces names in curly-braces. Compare, for example,

In [20]: 'cheese'.format(cheese='Roquefort')
Out[20]: 'cheese'

In [21]: '{cheese}'.format(cheese='Roquefort')
Out[21]: 'Roquefort'

I see you have lxml. Excellent. In that case, you could use lxml.builder to construct XML. This will help you create valid XML:

import lxml.etree as ET
import lxml.builder as builder
E = builder.E
F = builder.ElementMaker(namespace='http://foo', nsmap={'others':'http://foo'})

x = 2*5
xmlTemplate = ET.tostring(F.root(
    E.personal(
        F.sequence(
            E.feature(name='Michael',
                   age=str(x),
                   dob='15/10/1900')
            ), reference="500.txt")),
                          pretty_print=True)
print(xmlTemplate)

yields

<others:root xmlns:other="http://foo">
  <personal reference="500.txt">
    <others:sequence>
      <feature dob="15/10/1900" age="10" name="Michael"/>
    </others:sequence>
  </personal>
</others:root>

and this string can be parsed by lxml using:

doc = ET.fromstring(xmlTemplate)
print(doc)
# <Element {http://foo}root at 0xb741866c>
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • thank you so much. The first time I put the curly braces without inverted commas, and it didn't work. Then I removed it, I knew all along I needed curly braces but couldn't figure out how to use them. – Tiger1 Apr 06 '14 at 17:28
  • I'm having problem parsing the output xml. I use **Lxml** and it would not parse. can you give it a try? Thanks. – Tiger1 Apr 06 '14 at 17:42
  • The namespace prefix `others` needs to be defined. I've added some code above, showing how to define `others` in a root element. – unutbu Apr 06 '14 at 18:12
  • Will `.format` account for variables with apostrophes or quotation marks? (`description="Created by \"John Doe\" in 2016"`) – Stevoisiak Jan 29 '18 at 17:27
  • @StevenVascellaro: The `str.format` only performs literal string replacement. To automatically [escape quotation marks](https://stackoverflow.com/q/1222367/190597) it is easire to use `lxml.builder`. – unutbu Jan 29 '18 at 18:02