philipdotdev
philipdotdev

Reputation: 401

libxml2 - xpath and updating attributes

I have two xml files, A and B, and they have the same schema.

A.xml

<books>
    <book name="Alice in Wonderland" />
</books>

B.xml

<books>
    <book name="Of Mice and Men" />
    <book name="Harry Potter" />
</books>

I want to add the attribute source="B" in the list of books in B.xml and then copy the list over to A.xml, so that A.xml will look like this

<books>
    <book name="Alice in Wonderland" />
    <book name="Of Mice and Men" source="B" />
    <book name="Harry Potter" source="B" />
</books>

Can I use xpath to get the xpathobject of books from B, add the attribute, then copy the nodeset over to A? If so how would the code look like? Are there better ways than xpath to get the books from B?

Upvotes: 0

Views: 111

Answers (1)

zx485
zx485

Reputation: 29042

I guess the easiest way would be using an XSLT-processor. For this task an XSLT-1.0 processor is sufficient. You can use the following template to "merge" both files. Just use the XSLT-processor with the parameters a.xslt and a.xml. The second filename is specified in a.xslt.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
  <!-- This is the base filename of the second file without the extension '.xml' -->      
  <xsl:variable name="secondXMLFile" select="'b'" />    
  <!-- This changes the second filename to uppercase -->   
  <xsl:variable name="secondName" select="translate($secondXMLFile,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')" />    
  <!-- This adds the filename extension '.xml' to the base filename and creates a document() node -->                                     
  <xsl:variable name="second" select="document(concat($secondXMLFile,'.xml'))" />            

  <!-- identity template -->                     <!-- This copies all elements from the first file -->
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*" />
    </xsl:copy>
   </xsl:template>  

  <!-- modified identity template for second/other document -->  
  <xsl:template match="*" mode="sec">            <!-- This copies all 'book' elements from the second file -->
    <xsl:element name="{name()}">
      <xsl:apply-templates select="@*" />
      <xsl:attribute name="source"><xsl:value-of select="$secondName" /></xsl:attribute>
      <xsl:apply-templates select="node()" />     
    </xsl:element>
  </xsl:template>  

   <xsl:template match="/books">                 <!-- This initiates the copying of both files -->
    <xsl:copy>
        <xsl:apply-templates select="node()|@*" />
        <xsl:apply-templates select="$second/books/*" mode="sec" />
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

Upvotes: 1

Related Questions