XSLT transform not providing correct output

2020-05-10 09:13发布

问题:

I'm having a slight problem with my XSLT transform.

I have the following XSLT;

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"><!-- removes the unrelated elements -->
   <xsl:template match="@* | node()">
      <xsl:copy>
         <xsl:apply-templates select="@* | node()"/>
      </xsl:copy>
   </xsl:template>
   <xsl:template match="master_version[not(ORDER = //order/ORDERPK)]"/>
   <xsl:template match="press_section[not(ORDER = //order/ORDERPK)]"/>
   <xsl:template match="version[not(ORDER = //order/ORDERPK)]"/>
   <xsl:template match="task_info_press_section[not(ORDER = //order/ORDERPK)]"/>
   <xsl:template match="task_info_post_press[not(ORDER = //order/ORDERPK)]"/>
   <xsl:template match="post_press_version[not(ORDER = //order/ORDERPK)]"/>
   <!-- removes specified nodes from all elements -->
   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>
   <xsl:template match="ORDER"/>
   <xsl:template match="ORDERPK"/>
   <xsl:template match="PRESS_x0020_SECTION"/>
   <xsl:template match="POST_x0020_PRESS"/>
   <!-- Creates attributes against the ORDER element -->
   <xsl:strip-space elements="*"/>
   <xsl:output method="xml" indent="yes"/>
   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>
   <xsl:template match="order">
      <order job_id="{job_id}" site_code="{site_code}" replace="{replace}">
         <xsl:apply-templates/>
      </order>
   </xsl:template>
   <xsl:template match="job_id | site_code | replace | master_version"/>
   <!-- identity transform -->
   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>
   <xsl:template match="order">
      <order job_id="{@job_id}" site_code="{@site_code}" replace="{Replace}">
         <xsl:apply-templates select="node()"/>
         <xsl:copy-of select="../master_version"/>
      </order>
   </xsl:template>
   <xsl:template match="Replace | master_version"/>
   <!-- renames element to specified name -->
   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>
   <xsl:template match="task_info_press_section">
      <xsl:element name="task_info1">
         <xsl:apply-templates/>
      </xsl:element>
   </xsl:template>
   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>
   <xsl:template match="task_info_post_press">
      <xsl:element name="task_info2">
         <xsl:apply-templates/>
      </xsl:element>
   </xsl:template>
</xsl:stylesheet>

This is my original XML before transforming;

<?xml version="1.0" encoding="UTF-8"?>
<dataroot xmlns:od="urn:schemas-microsoft-com:officedata" generated="2015-01-07T16:58:58">

<order>
    <ORDERPK>3</ORDERPK>
    <job_id>S026500-1</job_id>
    <site_code>DG</site_code>
    <Replace>true</Replace>
    <job_description>TESTING</job_description>
    <order_qty>20000</order_qty>
    <finishing_style>PB</finishing_style>
    <depth>10</depth>
    <width>8</width>
    <cover_pagination>4</cover_pagination>
    <text_pagination>24</text_pagination>
    <delivery_commence_date>19/12/2014</delivery_commence_date>
    <delivery_complete_date>19/12/2014</delivery_complete_date>
    <job_site>DG</job_site>
    <managing_printer>DG</managing_printer>
    <is_managing_printer>True</is_managing_printer>
</order>
<master_version>
    <ORDER>1</ORDER>
    <version_id></version_id>
    <version_code>COMM</version_code>
    <version_common>true</version_common>
    <version_finished>false</version_finished>
    <version_description>Common</version_description>
    <version_nett_qty>176262</version_nett_qty>
    <version_special_qty>10</version_special_qty>
</master_version>
<master_version>
    <ORDER>2</ORDER>
    <version_code>COMM</version_code>
    <version_common>TRUE</version_common>
    <version_finished>FALSE</version_finished>
    <version_description>Common</version_description>
    <version_nett_qty>1900</version_nett_qty>
    <version_special_qty>0</version_special_qty>
</master_version>
<master_version>
    <ORDER>3</ORDER>
    <version_code>COMM</version_code>
    <version_common>true</version_common>
    <version_finished>false</version_finished>
    <version_description>common</version_description>
    <version_nett_qty>20000</version_nett_qty>
    <version_special_qty>0</version_special_qty>
</master_version>
<press_section>
    <ORDER>1</ORDER>
    <signature_id>001</signature_id>
    <sequence_id>1</sequence_id>
    <sequence_alpha>A</sequence_alpha>
    <description>4ppCover</description>
    <pagination>4</pagination>
    <trim_size>10.875 x 8.375</trim_size>
    <folio></folio>
    <data_format></data_format>
    <data_medium></data_medium>
    <data_due></data_due>
</press_section>
<press_section>
    <ORDER>1</ORDER>
    <signature_id>001</signature_id>
    <sequence_id>2</sequence_id>
    <sequence_alpha>A</sequence_alpha>
    <description>240ppText</description>
    <pagination>240</pagination>
    <trim_size>103875 x 8.25</trim_size>
</press_section>
<press_section>
    <ORDER>2</ORDER>
    <signature_id>001</signature_id>
    <sequence_id>1</sequence_id>
    <sequence_alpha>A</sequence_alpha>
    <description>4pp Cover</description>
    <pagination>4</pagination>
    <trim_size>10 x 8</trim_size>
</press_section>
<press_section>
    <ORDER>2</ORDER>
    <signature_id>001</signature_id>
    <sequence_id>2</sequence_id>
    <sequence_alpha>A</sequence_alpha>
    <description>12pp Text</description>
    <pagination>12</pagination>
    <trim_size>10 x 8</trim_size>
</press_section>
<press_section>
    <ORDER>3</ORDER>
    <signature_id>001</signature_id>
    <sequence_id>0</sequence_id>
    <sequence_alpha>A</sequence_alpha>
    <description>4pp Cover</description>
    <pagination>4</pagination>
    <trim_size>10 x 8</trim_size>
</press_section>
<press_section>
    <ORDER>3</ORDER>
    <signature_id>001</signature_id>
    <sequence_id>1</sequence_id>
    <sequence_alpha>A</sequence_alpha>
    <description>24pp Text</description>
    <pagination>24</pagination>
    <trim_size>10 x 8</trim_size>
</press_section>
<version>
    <ORDER>1</ORDER>
    <version_code>COMM</version_code>
</version>
<version>
    <ORDER>2</ORDER>
    <version_code>COMM</version_code>
</version>
<version>
    <ORDER>3</ORDER>
    <version_code>COMM</version_code>
</version>
<task_info_press_section>
    <ORDER>1</ORDER>
    <PRESS_x0020_SECTION>1</PRESS_x0020_SECTION>
    <task_sub_job_id>SC10268-001COMM</task_sub_job_id>
    <task_seq_id>0</task_seq_id>
    <task_description>4pp NEWS-NEWS COMM</task_description>
    <task_qty_rqd>9636</task_qty_rqd>
    <task_resource_id>1</task_resource_id>
    <task_mr_mins>120</task_mr_mins>
    <task_run_mins>240</task_run_mins>
    <task_run_speed>18000</task_run_speed>
    <task_notes>Task Notes</task_notes>
    <task_no_up>4</task_no_up>
    <task_deadline_date_time></task_deadline_date_time>
    <task_pdt>0.0</task_pdt>
</task_info_press_section>
<task_info_press_section>
    <ORDER>1</ORDER>
    <PRESS_x0020_SECTION>1</PRESS_x0020_SECTION>
    <task_sub_job_id>SC10268-1COMM</task_sub_job_id>
    <task_seq_id>0</task_seq_id>
    <task_description>Perfect Binding</task_description>
    <task_qty_rqd>19402</task_qty_rqd>
    <task_resource_id>1</task_resource_id>
    <task_mr_mins>120</task_mr_mins>
    <task_run_mins>240</task_run_mins>
    <task_run_speed>7500</task_run_speed>
    <task_notes>Task Notes</task_notes>
    <task_no_up>1</task_no_up>
    <task_deadline_date_time></task_deadline_date_time>
    <task_pdt>0.0</task_pdt>
</task_info_press_section>
<task_info_press_section>
    <ORDER>2</ORDER>
    <PRESS_x0020_SECTION>2</PRESS_x0020_SECTION>
    <task_sub_job_id>S019191-9-001COMM</task_sub_job_id>
    <task_seq_id>0</task_seq_id>
    <task_description>4pp Cover</task_description>
    <task_qty_rqd>1900</task_qty_rqd>
    <task_resource_id>2</task_resource_id>
    <task_mr_mins>20</task_mr_mins>
    <task_run_mins>63</task_run_mins>
    <task_run_speed>30</task_run_speed>
    <task_no_up>4</task_no_up>
    <task_pdt>0.0</task_pdt>
</task_info_press_section>
<task_info_press_section>
    <ORDER>2</ORDER>
    <PRESS_x0020_SECTION>2</PRESS_x0020_SECTION>
    <task_sub_job_id>S019191-9-1COMM</task_sub_job_id>
    <task_seq_id>0</task_seq_id>
    <task_description>Perfect Binding</task_description>
    <task_qty_rqd>1900</task_qty_rqd>
    <task_resource_id>2</task_resource_id>
    <task_mr_mins>20</task_mr_mins>
    <task_run_mins>120</task_run_mins>
    <task_run_speed>240</task_run_speed>
    <task_no_up>1</task_no_up>
    <task_pdt>0.0</task_pdt>
</task_info_press_section>
<task_info_press_section>
    <ORDER>3</ORDER>
    <PRESS_x0020_SECTION>3</PRESS_x0020_SECTION>
    <task_sub_job_id>S026500-1-001COMM</task_sub_job_id>
    <task_seq_id>0</task_seq_id>
    <task_description>4ppCover</task_description>
    <task_qty_rqd>20000</task_qty_rqd>
    <task_resource_id>2</task_resource_id>
</task_info_press_section>
<task_info_press_section>
    <ORDER>3</ORDER>
    <PRESS_x0020_SECTION>3</PRESS_x0020_SECTION>
    <task_sub_job_id>S026500-1-1COMM</task_sub_job_id>
    <task_seq_id>1</task_seq_id>
    <task_description>24ppText</task_description>
    <task_qty_rqd>20000</task_qty_rqd>
    <task_resource_id>2</task_resource_id>
</task_info_press_section>
<task_info_post_press>
    <ORDER>1</ORDER>
    <POST_x0020_PRESS>1</POST_x0020_PRESS>
    <task_sub_job_id>SC10268-1COMM</task_sub_job_id>
    <task_seq_id>0</task_seq_id>
    <task_description>Perfect Binding</task_description>
    <task_qty_rqd>19402</task_qty_rqd>
    <task_resource_id>10</task_resource_id>
    <task_mr_mins>120</task_mr_mins>
    <task_run_mins>240</task_run_mins>
    <task_run_speed>7500</task_run_speed>
    <task_notes>Task Notes</task_notes>
    <task_no_up>1</task_no_up>
    <task_deadline_date_time></task_deadline_date_time>
    <task_pdt>0.0</task_pdt>
</task_info_post_press>
<task_info_post_press>
    <ORDER>2</ORDER>
    <POST_x0020_PRESS>2</POST_x0020_PRESS>
    <task_sub_job_id>S019191-9-1COMM</task_sub_job_id>
    <task_seq_id>0</task_seq_id>
    <task_description>Perfect Binding</task_description>
    <task_qty_rqd>1900</task_qty_rqd>
    <task_resource_id>10</task_resource_id>
    <task_mr_mins>20</task_mr_mins>
    <task_run_mins>120</task_run_mins>
    <task_run_speed>240</task_run_speed>
    <task_no_up>1</task_no_up>
    <task_pdt>0.0</task_pdt>
</task_info_post_press>
<task_info_post_press>
    <ORDER>3</ORDER>
    <POST_x0020_PRESS>3</POST_x0020_PRESS>
    <task_sub_job_id>S026500-1-1COMM</task_sub_job_id>
    <task_seq_id>0</task_seq_id>
    <task_description>Perfect Binding</task_description>
    <task_qty_rqd>20000</task_qty_rqd>
    <task_resource_id>10</task_resource_id>
</task_info_post_press>
<post_press_version>
    <ORDER>1</ORDER>
    <post_press_version_op_id>0</post_press_version_op_id>
    <version_code>COMM</version_code>
    <post_press_resource_type>PB</post_press_resource_type>
</post_press_version>
<post_press_version>
    <ORDER>2</ORDER>
    <post_press_version_op_id>0</post_press_version_op_id>
    <version_code>COMM</version_code>
    <post_press_resource_type>PB</post_press_resource_type>
</post_press_version>
<post_press_version>
    <ORDER>3</ORDER>
    <post_press_version_op_id>0</post_press_version_op_id>
    <version_code>COMM</version_code>
    <post_press_resource_type>PB</post_press_resource_type>
</post_press_version>
</dataroot>

My XML should look like this (I have cut down some of the information to make viewing the important part easier);

<?xml version="1.0" encoding="UTF-8"?>
<dataroot xmlns:od="urn:schemas-microsoft-com:officedata"
          generated="2015-01-07T14:06:55">
   <order job_id="" site_code="" replace="true">
      <job_description>TESTDATA</job_description>
      <order_qty>1900</order_qty>
      <finishing_style>PB</finishing_style>
      <depth>10</depth>
      <width>8</width>
      <cover_pagination>4</cover_pagination>
      <text_pagination>12</text_pagination>
      <delivery_commence_date>15/12/2014</delivery_commence_date>
      <delivery_complete_date>15/12/2014</delivery_complete_date>
      <job_site>DG</job_site>
      <managing_printer>DG</managing_printer>
      <is_managing_printer>TRUE</is_managing_printer>
      <cust_order_ref>776031</cust_order_ref>
      <cust_code>Test</cust_code>
      <site_cce_name>Jamie</site_cce_name>
      <site_cce_email>JamesBrace@dstoutput.co.uk</site_cce_email>
      <sales_person_name>Jamie Brace</sales_person_name>
      <sales_person_email>JamesBrace@dstouput.co.uk</sales_person_email>
      <master_version>
         <version_id/>
         <version_code>COMM</version_code>
         <version_common>true</version_common>
         <version_finished>false</version_finished>
         <version_description>Common</version_description>
         <version_nett_qty>176262</version_nett_qty>
         <version_special_qty>10</version_special_qty>
      </master_version>
   </order>
</dataroot>

But it looks like this;

<?xml version="1.0" encoding="UTF-8"?>
<dataroot xmlns:od="urn:schemas-microsoft-com:officedata"
          generated="2015-01-07T14:06:55">
   <order job_id="" site_code="" replace="true">
      <job_description>TESTDATA</job_description>
      <order_qty>1900</order_qty>
      <finishing_style>PB</finishing_style>
      <depth>10</depth>
      <width>8</width>
      <cover_pagination>4</cover_pagination>
      <text_pagination>12</text_pagination>
      <delivery_commence_date>15/12/2014</delivery_commence_date>
      <delivery_complete_date>15/12/2014</delivery_complete_date>
      <job_site>DG</job_site>
      <managing_printer>DG</managing_printer>
      <is_managing_printer>TRUE</is_managing_printer>
      <cust_order_ref>776031</cust_order_ref>
      <cust_code>Test</cust_code>
      <site_cce_name>Jamie</site_cce_name>
      <site_cce_email>JamesBrace@dstoutput.co.uk</site_cce_email>
      <sales_person_name>Jamie Brace</sales_person_name>
      <sales_person_email>JamesBrace@dstouput.co.uk</sales_person_email>
      <master_version>
         <ORDER>1</ORDER>
         <version_id/>
         <version_code>COMM</version_code>
         <version_common>true</version_common>
         <version_finished>false</version_finished>
         <version_description>Common</version_description>
         <version_nett_qty>176262</version_nett_qty>
         <version_special_qty>10</version_special_qty>
      </master_version>
      <master_version>
         <ORDER>2</ORDER>
         <version_code>COMM</version_code>
         <version_common>TRUE</version_common>
         <version_finished>FALSE</version_finished>
         <version_description>Common</version_description>
         <version_nett_qty>1900</version_nett_qty>
         <version_special_qty>0</version_special_qty>
      </master_version>
   </order>
</dataroot>

The "master_version" element should be nested after the transform, which it is, but the transform is also telling it to delete all the element if the "ORDER" node in "master_version" is not equal to "ORDERPK" in "order", which it doesn't appear to be doing.

Any ideas?

Also I have been told that my XSLT isn't formatted very well, could anybody possibly help with that?

回答1:

There are a number of issues with your XSLT. Focusing on the problem in hand, one issue is in one of your "order" templates uses an xsl:copy-of

 <xsl:template match="order">
    <order job_id="{@job_id}" site_code="{@site_code}" replace="{Replace}">
        <xsl:apply-templates select="node()"/>
        <xsl:copy-of select="../master_version"/>
     </order>
 </xsl:template>

Before going further though, you have two templates matching "order". This is strictly speaking specified as an error in XSLT. You may not actually be seeing an error because some processors ignore the duplicate templates, and only use the last one. You should delete the first one.

Anyway, by using xsl:copy-of it is simply going to copy all master_version elements here, regardless of any other template matches here. You need to use xsl:apply-templates

<xsl:template match="order">
   <order job_id="{@job_id}" site_code="{@site_code}" replace="{Replace}">
      <xsl:apply-templates select="node()"/>
      <xsl:apply-templates select="../master_version"/>
   </order>
</xsl:template>

But this on its own will not work because of these two template matches (although it is an error to have to templates both matching just master_version as mentioned)

<xsl:template match="job_id | site_code | replace | master_version"/>

<xsl:template match="Replace | master_version"/>

Remove the master_version from these template matches, and leave just this existing one

<xsl:template match="master_version[not(ORDER = //order/ORDERPK)]"/>

(Note that when an element is matched with a condition, it will actually have a higher priority than one that just matched master_version, so this is not an error in this instance).

You would also be there at this point, but you would find now that master_version would still be output in their current place too. To get around this, you can have a template matching dataroot and add code to explicitly ignore the master_version elements at that point

<xsl:template match="dataroot">
  <xsl:copy>
     <xsl:apply-templates select="@*|node()[not(self::master_version)]"/>
  </xsl:copy>
</xsl:template>

Try this XSLT. It may not give the precise output you specified, but it should solve the problem on your master_version elements which you asked about:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

   <xsl:template match="master_version[not(ORDER = //order/ORDERPK)]"/>

   <xsl:template match="press_section[not(ORDER = //order/ORDERPK)]"/>
   <xsl:template match="version[not(ORDER = //order/ORDERPK)]"/>
   <xsl:template match="task_info_press_section[not(ORDER = //order/ORDERPK)]"/>
   <xsl:template match="task_info_post_press[not(ORDER = //order/ORDERPK)]"/>
   <xsl:template match="post_press_version[not(ORDER = //order/ORDERPK)]"/>
   <!-- removes specified nodes from all elements -->

   <xsl:template match="ORDER"/>
   <xsl:template match="ORDERPK"/>
   <xsl:template match="PRESS_x0020_SECTION"/>
   <xsl:template match="POST_x0020_PRESS"/>

   <!-- Creates attributes against the ORDER element -->
   <xsl:strip-space elements="*"/>
   <xsl:output method="xml" indent="yes"/>

   <xsl:template match="dataroot">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()[not(self::master_version)]"/>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="job_id | site_code | replace | Replace"/>

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

   <xsl:template match="order">
      <order job_id="{@job_id}" site_code="{@site_code}" replace="{Replace}">
         <xsl:apply-templates select="node()"/>
         <xsl:apply-templates select="../master_version"/>
      </order>
   </xsl:template>

   <xsl:template match="task_info_press_section">
      <xsl:element name="task_info1">
         <xsl:apply-templates/>
      </xsl:element>
   </xsl:template>

   <xsl:template match="task_info_post_press">
      <xsl:element name="task_info2">
         <xsl:apply-templates/>
      </xsl:element>
   </xsl:template>
</xsl:stylesheet>

Also note the multiple identity templates have been removed, as mentioned by Daniel Haley in comments.