Change values in XML based to those referenced in another XML file based on multiple match criteria

妖精的绣舞 提交于 2019-12-02 17:07:19

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!