简体   繁体   中英

How can I process child nodes the same way as parent nodes using multiple files as input in XSLT?

I am currently trying to process multiple files for specific nodes and collect them in a meaningful way to demonstrate the parent-child relationship but I'm having trouble getting past the first level of children.

A little background:

I'm attempting to collect procedure codes from a service manual. The manual is composed of several XMLs. The procedures these codes refer to sometimes refer to subprocedures, which in turn may refer to subprocedures. I want to list out all the procedure codes. If there is a subprocedure referenced in a procedure, I want to list its code as a child and continue in this way for all subprocedure until a procedure is listed that does not include a subprocedure.

So far, it's really easy for me to:

  • process all procedures (contained in a file list)
  • list the frt number for the procedure
  • from a given procedure, process all xref nodes found in cmd nodes and list the @keyref value.

The @keyref value is the same as the @id of the procedure to which it references. So, in a given procedure, any cmd/xref/@keyref value basically refers to a subprocedure. What I am attempting to capture is a list of all the @id values for procedures with subprocedures, and in turn, the @id of procedures that are subprocedures to subprocedures. I want to do this in a tree that makes the parent/child/descendant relationship clear in terms of what additional procedures someone needs to perform when performing a given procedure.

Something like this:

<service-manual>
  <procedure>
     <name>3 Way Coolant Valve - Chiller Bypass (Remove and Replace)</name>
     <frt-num>1234</frt-num>
     <child-proc>
        <frt-num>10040401</frt-num>
        <child-proc>
           <frt-num>3456</frt-num>
           ...
        </child-proc>
        <child-proc>
           <frt-num>4567</frt-num>
           ...
        </child-proc>
     </child-proc>
     <child-proc>
        <frt-num>15240701</frt-num>
        <child-proc>
           <frt-num>1111</frt-num>
           ...
        </child-proc>
        <child-proc>
           <frt-num>2222</frt-num>
           ...
        </child-proc>
     </child-proc>         
     ...
  </procedure>
...

What I am having trouble with is figuring out how to process all the procedures an xref refers to and list its children. What it needs to do is:

  • Figure out which task to which a given @keyref refers.
  • List the @id of that task as a child to the current context.
  • Continue processing all the @keyrefs in the same way in the decedent chain.

The result that I'm getting from my style sheet is only processing the first set of children.

Few things about this:

  • In all cases, the outermost task node is the only relevant @id value I'm concerned with. Nested task nodes do not factor into this exercise.
  • I want to capture all of this in a single XML.
  • There are over 500 files referenced in the file list. So, I am just offering a partial sample here.

The source XML looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE task
  PUBLIC "-//OASIS//DTD DITA Task//EN" "task.dtd">
<task id="X1234">
   <title>3 Way Coolant Valve - Chiller Bypass (Remove and Replace)</title>
   <taskbody>
      <prereq>
         <p><b>FRT No: 1234</b></p>
         <note conref="../../resources/SM-reuse.dita#topic_nsx_hq3_sl/Jack-Mode-Before-Lifting"/>
         <p conref="../../resources/SM-reuse.dita#topic_nsx_hq3_sl/12v-warnings"/>
      </prereq>
   </taskbody>
   <task id="d1e41176">
      <title><ph conref="../../resources/SM-reuse.dita#topic_nsx_hq3_sl/removal-title"/></title>
      <taskbody>
         <steps>
            <step>
               <cmd>Some content for the step <xref keyref="X10040401">(refer to procedure)</xref>. </cmd>
            </step>
            <step>
               <cmd><ph conref="../../resources/SM-reuse.dita#topic_nsx_hq3_sl/disconnect-12v"
                  /></cmd>
            </step>
            <step>
               <cmd>Some content for the steps <xref keyref="X15240701">(refer to
                     procedure)</xref>.</cmd>
            </step>
            <step>
               <cmd>Some content for the step</cmd>
            </step>
            <step>
               <cmd>Some content for the step</cmd>
            </step>
            <step>
               <cmd>Some content for the step</cmd>
               <stepxmp>
                  <fig>
                     <xref href="repairimages/tss00168.jpg" format="jpg">
<image href="repairthumbs/tss00168.jpg"/>
</xref>
                  </fig>
               </stepxmp>
            </step>
            <step>
               <cmd>Some content for the step</cmd>
            </step>
            <step>
               <cmd>Some content for the step</cmd>
               <stepxmp>
                  <fig>
                     <xref href="repairimages/tss00169.jpg" format="jpg">
<image href="repairthumbs/tss00169.jpg"/>
</xref>
                  </fig>
               </stepxmp>
            </step>
            <step>
               <cmd>Some content for the step</cmd>
               <stepxmp>
                  <fig>
                     <xref href="repairimages/tss00170.jpg" format="jpg">
<image href="repairthumbs/tss00170.jpg"/>
</xref>
                  </fig>
               </stepxmp>
            </step>
         </steps>
      </taskbody>
   </task>
   <task id="d1e41258">
      <title><ph conref="../../resources/SM-reuse.dita#topic_nsx_hq3_sl/installation-title"/></title>
      <taskbody>
         <steps>
            <step>
               <cmd><ph
                     conref="../../resources/SM-reuse.dita#topic_nsx_hq3_sl/Install-Reverse-Except"
                  /></cmd>
               <info>
                  <note conref="../../resources/SM-reuse.dita#topic_nsx_hq3_sl/Solvents-Ventilated"/>
                  <note conref="../../resources/SM-reuse.dita#topic_nsx_hq3_sl/Clean-Before-Install"/>
               </info>
            </step>
            <step>
               <cmd>Some content for the step</cmd>
            </step>
         </steps>
      </taskbody>
   </task>
</task>

I am using a file list XML as input for processing multiple source files that looks like this:

<directory name="source" size="327680" lastModified="1416254183623" date="20141117T115623" absolutePath="C:\transform_lab\service_manual_projects\frt_work\source" sort="name" reverse="false">
   <file name="12V_Positive_Jump_Post_(Remove_and_Replace).xml" size="3690" lastModified="1415930118927" date="20141113T175518" absolutePath="C:\transform_lab\service_manual_projects\frt_work\source\12V_Positive_Jump_Post_(Remove_and_Replace).xml"/>
   <file name="200A_Fuses_-_Wall_Connector_(Remove_and_Replace).xml" size="12837" lastModified="1415930118958" date="20141113T175518" absolutePath="C:\transform_lab\service_manual_projects\frt_work\source\200A_Fuses_-_Wall_Connector_(Remove_and_Replace).xml"/>
   <file name="2nd_Row_Center_Console_Assembly_(Remove_and_Replace).xml" size="2552" lastModified="1415930118990" date="20141113T175518" absolutePath="C:\transform_lab\service_manual_projects\frt_work\source\2nd_Row_Center_Console_Assembly_(Remove_and_Replace).xml"/>
   <file name="3_Way_Coolant_Valve_-_Chiller_Bypass_(Remove_and_Replace).xml" size="3788" lastModified="1415930119021" date="20141113T175519" absolutePath="C:\transform_lab\service_manual_projects\frt_work\source\3_Way_Coolant_Valve_-_Chiller_Bypass_(Remove_and_Replace).xml"/>
   ...
</directory>

The style sheet I've developed looks like this:

<xsl:template match ="directory">
    <service-manual>
        <xsl:apply-templates select="file"/> 
    </service-manual>        
</xsl:template >

<xsl:template match="file">     
    <xsl:variable name="path" select="@name"/>
    <xsl:for-each select="document($path)/*">
        <xsl:for-each select="/*">
            <procedure>
                <name>
                    <xsl:value-of select="title"/>
                </name>
                <frt-num>
                    <xsl:value-of select="substring-after(@id,'X')"/>
                </frt-num>                    
                <xsl:apply-templates select="//cmd"/>
            </procedure>
        </xsl:for-each>
    </xsl:for-each>
</xsl:template>

<xsl:template match="//cmd">
    <xsl:for-each select="xref">
        <child-proc>
            <frt-num>
                <xsl:value-of select="substring-after(@keyref,'X')"/>
            </frt-num>                
            <xsl:apply-templates select="file"/>
        </child-proc>            
    </xsl:for-each>
</xsl:template>

Obviously, this is wrong. My thought was that I should create a template that processes the xref nodes and then call that template from the //cmd template but that didn't work much better. Is that the direction I should be taking with this? Also, is using modes an option here? Being that I'm a bit of an amateur, the logic involved with successfully accomplishing this has my brain twisted up a bit. Any help appreciated.

One approach I thought about but wasn't sure how to make work is using key() to do a lookup in the key map that is used to manage linked resources. The value of @keyref maps to the value of the @keya attribute on keydef elements. All keydef elements are collected in a map that is separate from the service manual content. The key map for this project looks like this:

<map processing-role="resource-only">
    <title>Service Manual Link Map</title>
    <keydef keys="X1234"
       href="../section_maps/topics/3_Way_Coolant_Valve_-_Chiller_Bypass_(Remove_and_Replace).xml"/>
    ...
    <keydef keys="X10040401"
       href="../section_maps/topics/Raise_Vehicle_-_2_Post_Lift.xml"/>
    <keydef keys="X15240701"
       href="../section_maps/topics/Raise_Vehicle_-_4_Post_Lift.xml"/>
    ...
</map>

Now that I think about it, any solution I come up with must include a lookup in the key map because that is the only way of knowing for sure to what task a given @keyref maps.

Many things are still unclear, but it might be easier for you to comment on an attempted solution. Let me know what I have not quite understood.

I have used your input XML, but I have made changes to the directory file. It now only contains one file reference (since I only have the one you show):

<directory name="source" size="327680" lastModified="1416254183623" date="20141117T115623" absolutePath="C:\transform_lab\service_manual_projects\frt_work\source" sort="name" reverse="false">
   <file name="12V_Positive_Jump_Post_(Remove_and_Replace).xml" size="3690" lastModified="1415930118927" date="20141113T175518" absolutePath="C:\transform_lab\service_manual_projects\frt_work\source\12V_Positive_Jump_Post_(Remove_and_Replace).xml"/>
</directory>

Stylesheet

You can do away with most of the xsl:for-each constructs, some of them are just superfluous, others are best replaced with a template.

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

    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/directory">
        <service-manual>
            <xsl:apply-templates select="file"/> 
        </service-manual>        
    </xsl:template>

    <xsl:template match="file">     
        <xsl:variable name="path" select="@name"/>
        <xsl:for-each select="document($path)/task">
                <procedure>
                    <name>
                        <xsl:value-of select="title"/>
                    </name>
                    <frt-num>
                        <xsl:value-of select="substring-after(@id,'X')"/>
                    </frt-num>                    
                    <xsl:apply-templates/>
                </procedure>
        </xsl:for-each>
    </xsl:template>

    <xsl:template match="xref|task/task">
            <child-proc>
                <frt-num>
                    <xsl:value-of select="substring-after(@keyref,'X')"/>
                </frt-num>                
                <xsl:apply-templates/>
            </child-proc>            
    </xsl:template>

    <xsl:template match="text()"/>

</xsl:stylesheet>

XML Output

As you can see, some of the frt-num elements are empty, because some of the xref elements do not have an @keyref attribute. In which case, I suspect, they do not reference another subprocess.

<?xml version="1.0" encoding="UTF-8"?>
<service-manual>
   <procedure>
      <name>3 Way Coolant Valve - Chiller Bypass (Remove and Replace)</name>
      <frt-num>1234</frt-num>
      <child-proc>
         <frt-num/>
         <child-proc>
            <frt-num>10040401</frt-num>
         </child-proc>
         <child-proc>
            <frt-num>15240701</frt-num>
         </child-proc>
         <child-proc>
            <frt-num/>
         </child-proc>
         <child-proc>
            <frt-num/>
         </child-proc>
         <child-proc>
            <frt-num/>
         </child-proc>
      </child-proc>
      <child-proc>
         <frt-num/>
         <child-proc>
            <frt-num>46010000</frt-num>
         </child-proc>
      </child-proc>
   </procedure>
</service-manual>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM