问题
I have a large XML file and need to change certain values to those in another XML document based on multiple matching criteria.
My large XML file 'file1.xml' is in the following format:
<institution>
<ukprn>1234</ukprn>
<course>
<courseID>1</courseID>
<courseaim>X99</courseaim>
</course>
<student>
<birthdate>30/10/1985</birthdate>
<instance>
<OWNINST>1558310|1</OWNINST>
<FC>1</FC>
<STULOAD>100</STULOAD>
<elq>4</elq>
<MODE>31</MODE>
<StudentOnModule>
<MODID>08|29400</MODID>
<MODOUT>4</MODOUT>
</StudentOnModule>
<StudentOnModule>
<MODID>08|29091</MODID>
<MODOUT>4</MODOUT>
</StudentOnModule>
</instance>
</student>
<student>
<birthdate>01/02/1999</birthdate>
<instance>
<OWNINST>654321|1</OWNINST>
<FC>2</FC>
<elq>2</elq>
<StudentOnModule>
<MODID>02|37522</MODID>
<MODOUT>6</MODOUT>
</StudentOnModule>
<StudentOnModule>
<MODID>02|48966</MODID>
<MODOUT>1</MODOUT>
</StudentOnModule>
</instance>
<instance>
<OWNINST>654321|2</OWNINST>
<FC>6</FC>
<elq>1</elq>
<StudentOnModule>
<MODID>08|29400</MODID>
<MODOUT>4</MODOUT>
</StudentOnModule>
<StudentOnModule>
<MODID>08|29091</MODID>
<MODOUT>4</MODOUT>
</StudentOnModule>
</instance>
</student>
</institution>
I have a second file 'file2.xml' which contains the data to update 'file1.xml' with. It is structured like this:
<studentstoamend>
<student><OWNINST>1558310|1</OWNINST><MODID>08|29400</MODID><MODOUT>6</MODOUT></student>
<student><OWNINST>1558310|1</OWNINST><MODID>08|29091</MODID><MODOUT>6</MODOUT></student>
</studentstoamend>
For each student in 'File2.xml' I want to update the MODOUT in File1.xml to become the value in File2.xml. For example, in File1.xml: OWNINST=1558310|1, MODID=08|29400 has MODOUT=4 but File2.xml specifies that MODOUT=6 so File1.xml should be updated to MODOUT=6 for that particular OWNINST / MODOUT combination. The output file should be an exact copy of file1.xml but with the changes specified in File2.xml.
Please could you help with this as I don't seem to be able to make it work.
This is how far I got:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="no"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Student/Instance[OWNINST = document('file2.xml')/studentstoamend/STUDENT/OWNINST/MODID]/MODOUT">
<xsl:copy-of select="document('file2.xml')/studentstoamend/STUDENT[OWNINST = current()/../OWNINST]/MODID[MODID = current()/MODID]/MODOUT"/>
</xsl:template>
</xsl:stylesheet>
So the output file should be:
<institution>
<ukprn>1234</ukprn>
<course>
<courseID>1</courseID>
<courseaim>X99</courseaim>
</course>
<student>
<birthdate>30/10/1985</birthdate>
<instance>
<OWNINST>1558310|1</OWNINST>
<FC>1</FC>
<STULOAD>100</STULOAD>
<elq>4</elq>
<MODE>31</MODE>
<StudentOnModule>
<MODID>08|29400</MODID>
<MODOUT>6</MODOUT>
</StudentOnModule>
<StudentOnModule>
<MODID>08|29091</MODID>
<MODOUT>6</MODOUT>
</StudentOnModule>
</instance>
</student>
<student>
<birthdate>01/02/1999</birthdate>
<instance>
<OWNINST>654321|1</OWNINST>
<FC>2</FC>
<elq>2</elq>
<StudentOnModule>
<MODID>02|37522</MODID>
<MODOUT>6</MODOUT>
</StudentOnModule>
<StudentOnModule>
<MODID>02|48966</MODID>
<MODOUT>1</MODOUT>
</StudentOnModule>
</instance>
<instance>
<OWNINST>654321|2</OWNINST>
<FC>6</FC>
<elq>1</elq>
<StudentOnModule>
<MODID>08|29400</MODID>
<MODOUT>4</MODOUT>
</StudentOnModule>
<StudentOnModule>
<MODID>08|29091</MODID>
<MODOUT>4</MODOUT>
</StudentOnModule>
</instance>
</student>
</institution>
Thanks so much for looking at this. Martin
回答1:
The main thing to note is XML (and XSLT) is case-sensitive, and so a template that contains Student
in the path is not going to match a student
element in your XML.
Another issue is that you have missed out elements from the path, for example StudentOnModule
is the parent of MODOUT
, not instance.
Try this template....
<xsl:template match="student/instance[OWNINST = document('file2.xml')/studentstoamend/student/OWNINST]/StudentOnModule/MODOUT">
<xsl:copy-of select="document('file2.xml')/studentstoamend/student[OWNINST = current()/../../OWNINST][MODID = current()/../MODID]/MODOUT"/>
</xsl:template>
Note, I might be tempted to simplify the template, to avoid having to reference the second file twice....
<xsl:template match="MODOUT">
<xsl:variable name="modout" select="document('file2.xml')/studentstoamend/student[OWNINST = current()/../../OWNINST][MODID = current()/../MODID]/MODOUT" />
<xsl:choose>
<xsl:when test="$modout">
<xsl:copy-of select="$modout" />
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="." />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
来源:https://stackoverflow.com/questions/46952701/change-values-in-xml-based-to-those-referenced-in-another-xml-file-based-on-mult