1

I would like to pass a certain parameter to an xml, so instead of being a raw xml with all the values by the creation of it, I'd like to change one with a parameter (a user input, for example).

Ideally, I was looking for something like <title> &param1 </title>and be able later on to pass whatever param I would like, but I guess it cannot be done.

So like passing a parameter cannot be done (or at least from what I have searched), I thought about editing the xml after it's created.

I have searched mostly with beautifulsoup, because it is what I want to use (and what I am using). This is only a little bit of my project. for example this and this are some of my research).

So this is the function I am trying to do: We have an xml, we find the part we want to edit, and we edit it (I know that to access it, it needs to be an integer pruebaEdit[anyString]is not correct.

def editXMLTest():
    editTest="""<?xml version="1.0" ?>
<books>
  <book>
    <title>moon</title>
    <author>louis</author>
    <price>8.50</price>
  </book>
</books>
    """
    soup =BeautifulSoup(editTest)
    for tag in soup.find_all('title'):
        print (tag.string, '\n')
        #tag.string='invented title'
        editTest[tag]='invented title' #I know it has to be an integer, not a string
    print()
    print(editTest)

My expected output should be in the xml: <title>invented title</title> instead of <title>moon</title>.

Edit: added this to my research

Louis Storming
  • 151
  • 1
  • 10

4 Answers4

2

you have to print the results or soup not original string editTest

for tag in soup.find_all('title'):
    print (tag.string, '\n')
    tag.string='invented title'
print(soup)
ewwink
  • 18,382
  • 2
  • 44
  • 54
  • Thanks... That was kind of stupid. I tried doing it with `cleanSoup = BeautifulSoup(str(soup).replace('moon', valueToChange))`But this works far way better, shame I did not print it properly. Thanks!! – Louis Storming Jan 03 '19 at 10:42
1

Using entity references like &param; is the closest thing available in XML itself, but it's not very flexible because the entity expansions are defined in a DTD file rather than being supplied programmatically to the XML parser. Some parsers (I don't know the Python situation) allow you to supply an EntityResolver which can resolve entity references programmatically, but it wouldn't be my first choice of approach.

There are of course templating languages that allow XML to be constructed programmatically. XSLT is the most obvious choice; it probably does a lot more than you need, but that's not necessarily a drawback. Some other options are listed at https://en.wikipedia.org/wiki/Comparison_of_web_template_engines -- including a handful for the Python environment. Unfortunately many of these tools, in my experience, are not particularly well documented or supported, so do your research carefully.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
1

With Python's lxml that can run XSLT 1.0 scripts and also the parsing engine to BeautifulSoup, you can pass parameters to modify XML files as needed. Simply set the <xsl:param> in XSLT script and in Python pass value via strparam:

XSLT (save as .xsl file, a special .xml file)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes" omit_xml_declaration="no"/>
  <xsl:strip-space elements="*"/>

  <!-- INITIALIZE PARAMETER -->
  <xsl:param name="new_title" /> 

  <!-- IDENTITY TRANSFORM -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- REWRITE TITLE TEXT -->
  <xsl:template match="title">
    <xsl:copy>
      <xsl:value-of select="$new_title"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

Python (see output below as comment)

import lxml.etree as et

txt = '''<books>
           <book>
               <title>moon</title>
               <author>louis</author>
               <price>8.50</price>
             </book>
         </books>'''

# LOAD XSL SCRIPT
xml = et.fromstring(txt)
xsl = et.parse('/path/to/XSLTScript.xsl')
transform = et.XSLT(xsl)

# PASS PARAMETER TO XSLT
n = et.XSLT.strparam('invented title')
result = transform(doc, new_title=n)

print(result)
# <?xml version="1.0"?>
# <books>
#   <book>
#     <title>invented title</title>
#     <author>louis</author>
#     <price>8.50</price>
#   </book>
# </books>

# SAVE XML TO FILE
with open('Output.xml', 'wb') as f:
    f.write(result)

Pyfiddle Demo (be sure to click run and check output)

Parfait
  • 104,375
  • 17
  • 94
  • 125
-1

Use <xsl> tag to pass a parameter in xml