0

I am finding elements from XML1 in XML2 and after that i want to insert one comment XML1 is:

<Price>
    <Amount>100</Amount>
    <Amount>102</Amount>
    <Amount>103</Amount>
</Price>

and XML2 is:

<List>
    <Item>
        <Price>
            <Amount>100</Amount>
            <Next_Item>
                <Name>Apple</Name>
            </Next_Item>
            <Next_Item>
                <Name>Orange</Name>
            </Next_Item>
        </Price>
         <Price>
            <Amount>200</Amount>
            <Next_Item>
                <Name>Apple</Name>
            </Next_Item>
            <Next_Item>
                <Name>Orange</Name>
            </Next_Item>
        </Price>
    </Item>
</List>

Output XML i want is following where I want to insert a comment above Price if the value is matching from price/amount from XML2:

<List>
    <Item>
      <!--important-->
        <Price>
            <Amount>100</Amount>
            <Next_Item>
                <Name>Apple</Name>
            </Next_Item>
            <Next_Item>
                <Name>Orange</Name>
            </Next_Item>
        </Price>
         <Price>
            <Amount>200</Amount>
            <Next_Item>
                <Name>Apple</Name>
            </Next_Item>
            <Next_Item>
                <Name>Orange</Name>
            </Next_Item>
        </Price>
    </Item>
</List>

After getting help from this forum I tried coding like this:

xml1 = etree.parse('C:/Python/XML1.xml')
xml2 = etree.parse('C:/Python/XML2.xml')
for am in xml1.xpath('//Price/Id/text()'):
    x = xml2.xpath(f'//List/Item/Price[./Amount/text()="{am}"]')
    if len(x)>0:
        root = xml2.find('.//List/Item/Price')
        root.insert(1, etree.Comment('important'))
        etree.dump(root)
with open('C:/Python/output.xml','w') as f:
    f.write(etree.Comment(root))

I am not able to get proper output xml I am getting error: AttributeError: 'NoneType' object has no attribute 'insert'

Grateful for any kind of help.

2 Answers 2

1

Since you need to compare across documents and traverse multiple nodes with conditional logic to add comment, consider XSLT, the special-purpose language designed to transform XML files. Python's lxml library can run XSLT 1.0 scripts. Also, XSLT maintains the document function to parse from other documents.

Specifically, below XSLT runs the identity transform to copy document as is and then conditionally adds comment before <Price> element. Notice XSLT references the First_Document.xml and Python references the Second_Document.xml. Be sure file in document() is in same location to second document.

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 method="xml" omit-xml-declaration="yes" encoding="utf-8" indent="yes" />
    <xsl:strip-space elements="*"/>

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

    <!-- UPDATE Item NODES -->
    <xsl:template match="Item">
     <xsl:copy>
       <!-- MAP THROUGH Price NODES -->
       <xsl:for-each select="Price">
         <!-- CONDITIONALLY ADD COMMENT -->
         <xsl:variable name="curr_amount" select="Amount"/>
         <xsl:if test="document('First_Document.xml')/Price/Amount = $curr_amount">
           <xsl:comment>important</xsl:comment>
         </xsl:if>
         <!-- ALWAYS RE-WRITE Price NODES -->         
         <xsl:copy>
             <xsl:apply-templates select="*"/>
         </xsl:copy>
       </xsl:for-each>
     </xsl:copy>
    </xsl:template> 
</xsl:stylesheet>

Python

from lxml import etree

# LOAD XML AND XSLT
xml = etree.parse("Second_Document.xml")
xsl = etree.parse("My_StyleSheet.xsl")

# CONFIGURE AND RUN TRANSFORMER
transformer = etree.XSLT(xsl)
result = transformer(xml)

# SAVE TRANSFORMATION TO FILE
result.write_output("Output.xml")

Output

<List>
  <Item>
    <!--important-->
    <Price>
      <Amount>100</Amount>
      <Next_Item>
        <Name>Apple</Name>
      </Next_Item>
      <Next_Item>
        <Name>Orange</Name>
      </Next_Item>
    </Price>
    <Price>
      <Amount>200</Amount>
      <Next_Item>
        <Name>Apple</Name>
      </Next_Item>
      <Next_Item>
        <Name>Orange</Name>
      </Next_Item>
    </Price>
  </Item>
</List>
Sign up to request clarification or add additional context in comments.

Comments

0

Try the below

import xml.etree.ElementTree as ET


xml1 = '''<Price>
    <Amount>100</Amount>
    <Amount>102</Amount>
    <Amount>103</Amount>
</Price>'''

xml2 = ''' <List>
    <Item>
        <Price>
            <Amount>100</Amount>
            <Next_Item>
                <Name>Apple</Name>
            </Next_Item>
            <Next_Item>
                <Name>Orange</Name>
            </Next_Item>
        </Price>
         <Price>
            <Amount>200</Amount>
            <Next_Item>
                <Name>Apple</Name>
            </Next_Item>
            <Next_Item>
                <Name>Orange</Name>
            </Next_Item>
        </Price>
    </Item>
</List>
'''

root1 = ET.fromstring(xml1)
root2 = ET.fromstring(xml2)
amounts = set(e.text for e in root1.findall('.//Amount'))
for item in root2.findall('.//Item'):
    prices = item.findall('.//Price')
    for price in prices:
        amount = price.find('Amount').text
        if amount in amounts:
            item.insert(0, ET.Comment('Important'))
ET.dump(root2)

output

<List>
    <Item>
        <!--Important-->
        <Price>
            <Amount>100</Amount>
            <Next_Item>
                <Name>Apple</Name>
            </Next_Item>
            <Next_Item>
                <Name>Orange</Name>
            </Next_Item>
        </Price>
         <Price>
            <Amount>200</Amount>
            <Next_Item>
                <Name>Apple</Name>
            </Next_Item>
            <Next_Item>
                <Name>Orange</Name>
            </Next_Item>
        </Price>
    </Item>
</List>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.