使用key()进行查找时,如何将模板的输出限制为单个值

时间:2015-04-11 00:16:15

标签: xml xslt

我有一个零件手册,它由一组由不同零件组分割的几个XML文件组成。每个零件分组包含几个与各个零件相关的信息表,包括唯一的零件号。每个单独的部分都包含在表格中的单行中。我在这些表中添加了一个空列,指出一旦我通过变换运行它,某个部件的销售是否受到“是”或“否”值的限制。

我编写了一个XSLT转换来查找查找文件中的部件号,将其与我正在处理的文档中的部件号进行比较,当它们匹配时,用“是”或“否”填充空列。基于查找XML文档中列出的内容。

零件编号是唯一的。但是,某些部件与多个部件组一起使用。虽然部件手册由几个XML文件组成,但我使用的查找文件基于BOM。因此,它是一个包含每个组的所有部分的大型XML文档。

我正在处理的XML文档如下所示:

<reference>
    <title>Part Group A</title>
    <refbody>
        <section>
            <image href="partGroupA.svg"/>
        </section>
        <simpletable>
            <sthead>
                <stentry>Annotation</stentry>
                <stentry>Part Name</stentry>
                <stentry>Restricted?</stentry>
                <stentry>Part Description</stentry>
                <stentry>Part Number</stentry>
                <stentry>Quantity</stentry>
                <stentry>Comment</stentry>
            </sthead>
            <strow>
                <stentry translate="no" props="annotation">1</stentry>
                <stentry translate="no" props="part-name">SomePart</stentry>
                <stentry translate="no" props="part-restrict"></stentry>
                <stentry translate="yes" props="part-desc">SomePart</stentry>
                <stentry translate="no" props="part-number">1234567-00-A</stentry>
                <stentry translate="no" props="quantity">1</stentry>
                <stentry translate="yes" props="comment">Some comment</stentry>
            </strow>
            <strow>
                <stentry translate="no" props="annotation">2</stentry>
                <stentry translate="no" props="part-name">AnotherPart</stentry>
                <stentry translate="no" props="part-restrict"></stentry>
                <stentry translate="yes" props="part-desc">AnotherPart</stentry>
                <stentry translate="no" props="part-number">2345678-00-A</stentry>
                <stentry translate="no" props="quantity">1</stentry>
                <stentry translate="yes" props="comment">Another comment</stentry>
            </strow>
            ...
        </simpletable>
    </refbody>
</reference>

查找XML文档包含:

...
<strow>
  <stentry props="part-section">Part Group A</stentry>
  <stentry props="part-name">SomePart</stentry>
  <stentry props="part-number">1234567-00-A</stentry>
  <stentry props="part-restrict">Yes</stentry>
</strow>
<strow>
   <stentry props="part-section">Part Group A</stentry>
   <stentry props="part-name">AnotherPart</stentry>
   <stentry props="part-number">2345678-00-A</stentry>
   <stentry props="part-restrict">No</stentry>
</strow>
...
<strow>
  <stentry props="part-section">Part Group B</stentry>
  <stentry props="part-name">SomePart</stentry>
  <stentry props="part-number">1234567-00-A</stentry>
  <stentry props="part-restrict">No</stentry>
</strow>
...

我的XSLT转换如下所示:

<xsl:output method="xml" encoding="UTF-8" indent="yes" doctype-system="reference.dtd" doctype-public="-//OASIS//DTD DITA Reference//EN"/>
<xsl:strip-space elements="*"/>

<xsl:key name="part-number" match="strow" use="stentry[@props='part-number']" />

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

<xsl:template match="stentry[@props='part-restrict']">
    <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <xsl:variable name="matching-part" select="key('part-number', ../stentry[@props='part-number'], document('pm_restrict_redo-2.xml'))" />
        <xsl:choose>
            <xsl:when test="$matching-part">
                <xsl:value-of select="$matching-part/stentry[@props='part-restrict']"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="."/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:copy>
</xsl:template>

这很有用。由于在某些情况下,零件号在不同的零件组中使用多次(对于不同的系统,子系统等)并且在BOM查找中多次列出,我的转换最终会列出每个“是”或“否”发生的部分。生成的XML如下所示:

<strow>
        <stentry translate="no" props="annotation">1</stentry>
        <stentry translate="no" props="part-name">SomePart</stentry>
        <stentry translate="no" props="part-restrict">yes no</stentry>
        <stentry translate="yes" props="part-desc">SomePart</stentry>
        <stentry translate="no" props="part-number">1234567-00-A</stentry>
        <stentry translate="no" props="quantity">1</stentry>
        <stentry translate="yes" props="comment">Some comment</stentry>
</strow>

我要做的是转换与特定零件组相关的XML,并将“是”或“否”值的列表限制为为该零件组捕获的值。相反,我得到的是BOM中每个零件出现的所有“是”和“否”值。

任何帮助表示感谢。

2 个答案:

答案 0 :(得分:1)

以下是您转型的即时解决方法。 为了方便起见,我已经内联了查找文档,这使得转换看起来很长,但它实际上简短而直接:

<xsl:stylesheet version="2.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/> 

 <xsl:key name="part-number" match="strow" 
 use="concat(stentry[@props='part-section'], '|', stentry[@props='part-number'])" />

 <xsl:variable name="vLookup">
  <lookup>
        <strow>
            <stentry props="part-section">Part Group A</stentry>
            <stentry props="part-name">SomePart</stentry>
            <stentry props="part-number">1234567-00-A</stentry>
            <stentry props="part-restrict">Yes</stentry>
        </strow>
        <strow>
            <stentry props="part-section">Part Group A</stentry>
            <stentry props="part-name">AnotherPart</stentry>
            <stentry props="part-number">2345678-00-A</stentry>
            <stentry props="part-restrict">No</stentry>
        </strow>
        <strow>
            <stentry props="part-section">Part Group B</stentry>
            <stentry props="part-name">SomePart</stentry>
            <stentry props="part-number">1234567-00-A</stentry>
            <stentry props="part-restrict">No</stentry>
        </strow>
    </lookup>
 </xsl:variable>  

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

 <xsl:template match="stentry[@props='part-restrict']">
    <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <xsl:variable name="matching-part" 
             select="key('part-number', 
                         concat(ancestor::refbody[1]/preceding-sibling::title[1], 
                         '|',
                         ../stentry[@props='part-number']), 
                     $vLookup)" />
         <xsl:sequence select=
           "($matching-part/stentry[@props='part-restrict'], 
             .[empty($matching-part)])/text()"/>
    </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

在提供的源XML文档上应用此转换时

<reference>
    <title>Part Group A</title>
    <refbody>
        <section>
            <image href="partGroupA.svg"/>
        </section>
        <simpletable>
            <sthead>
                <stentry>Annotation</stentry>
                <stentry>Part Name</stentry>
                <stentry>Restricted?</stentry>
                <stentry>Part Description</stentry>
                <stentry>Part Number</stentry>
                <stentry>Quantity</stentry>
                <stentry>Comment</stentry>
            </sthead>
            <strow>
                <stentry translate="no" props="annotation">1</stentry>
                <stentry translate="no" props="part-name">SomePart</stentry>
                <stentry translate="no" props="part-restrict"></stentry>
                <stentry translate="yes" props="part-desc">SomePart</stentry>
                <stentry translate="no" props="part-number">1234567-00-A</stentry>
                <stentry translate="no" props="quantity">1</stentry>
                <stentry translate="yes" props="comment">Some comment</stentry>
            </strow>
            <strow>
                <stentry translate="no" props="annotation">2</stentry>
                <stentry translate="no" props="part-name">AnotherPart</stentry>
                <stentry translate="no" props="part-restrict"></stentry>
                <stentry translate="yes" props="part-desc">AnotherPart</stentry>
                <stentry translate="no" props="part-number">2345678-00-A</stentry>
                <stentry translate="no" props="quantity">1</stentry>
                <stentry translate="yes" props="comment">Another comment</stentry>
            </strow>
        </simpletable>
    </refbody>
    <title>Part Group B</title>
    <refbody>
        <section>
            <image href="partGroupB.svg"/>
        </section>
        <simpletable>
            <sthead>
                <stentry>Annotation</stentry>
                <stentry>Part Name</stentry>
                <stentry>Restricted?</stentry>
                <stentry>Part Description</stentry>
                <stentry>Part Number</stentry>
                <stentry>Quantity</stentry>
                <stentry>Comment</stentry>
            </sthead>
            <strow>
                <stentry translate="no" props="annotation">1</stentry>
                <stentry translate="no" props="part-name">SomePart</stentry>
                <stentry translate="no" props="part-restrict"></stentry>
                <stentry translate="yes" props="part-desc">SomePart</stentry>
                <stentry translate="no" props="part-number">1234567-00-A</stentry>
                <stentry translate="no" props="quantity">1</stentry>
                <stentry translate="yes" props="comment">Some comment</stentry>
            </strow>
            <strow>
                <stentry translate="no" props="annotation">2</stentry>
                <stentry translate="no" props="part-name">AnotherPart</stentry>
                <stentry translate="no" props="part-restrict"></stentry>
                <stentry translate="yes" props="part-desc">AnotherPart</stentry>
                <stentry translate="no" props="part-number">2345678-00-A</stentry>
                <stentry translate="no" props="quantity">1</stentry>
                <stentry translate="yes" props="comment">Another comment</stentry>
            </strow>
        </simpletable>
    </refbody>
</reference>

产生了想要的正确结果

<reference>
   <title>Part Group A</title>
   <refbody>
      <section>
         <image href="partGroupA.svg"/>
      </section>
      <simpletable>
         <sthead>
            <stentry>Annotation</stentry>
            <stentry>Part Name</stentry>
            <stentry>Restricted?</stentry>
            <stentry>Part Description</stentry>
            <stentry>Part Number</stentry>
            <stentry>Quantity</stentry>
            <stentry>Comment</stentry>
         </sthead>
         <strow>
            <stentry translate="no" props="annotation">1</stentry>
            <stentry translate="no" props="part-name">SomePart</stentry>
            <stentry translate="no" props="part-restrict">Yes</stentry>
            <stentry translate="yes" props="part-desc">SomePart</stentry>
            <stentry translate="no" props="part-number">1234567-00-A</stentry>
            <stentry translate="no" props="quantity">1</stentry>
            <stentry translate="yes" props="comment">Some comment</stentry>
         </strow>
         <strow>
            <stentry translate="no" props="annotation">2</stentry>
            <stentry translate="no" props="part-name">AnotherPart</stentry>
            <stentry translate="no" props="part-restrict">No</stentry>
            <stentry translate="yes" props="part-desc">AnotherPart</stentry>
            <stentry translate="no" props="part-number">2345678-00-A</stentry>
            <stentry translate="no" props="quantity">1</stentry>
            <stentry translate="yes" props="comment">Another comment</stentry>
         </strow>
      </simpletable>
   </refbody>
   <title>Part Group B</title>
   <refbody>
      <section>
         <image href="partGroupB.svg"/>
      </section>
      <simpletable>
         <sthead>
            <stentry>Annotation</stentry>
            <stentry>Part Name</stentry>
            <stentry>Restricted?</stentry>
            <stentry>Part Description</stentry>
            <stentry>Part Number</stentry>
            <stentry>Quantity</stentry>
            <stentry>Comment</stentry>
         </sthead>
         <strow>
            <stentry translate="no" props="annotation">1</stentry>
            <stentry translate="no" props="part-name">SomePart</stentry>
            <stentry translate="no" props="part-restrict">No</stentry>
            <stentry translate="yes" props="part-desc">SomePart</stentry>
            <stentry translate="no" props="part-number">1234567-00-A</stentry>
            <stentry translate="no" props="quantity">1</stentry>
            <stentry translate="yes" props="comment">Some comment</stentry>
         </strow>
         <strow>
            <stentry translate="no" props="annotation">2</stentry>
            <stentry translate="no" props="part-name">AnotherPart</stentry>
            <stentry translate="no" props="part-restrict"/>
            <stentry translate="yes" props="part-desc">AnotherPart</stentry>
            <stentry translate="no" props="part-number">2345678-00-A</stentry>
            <stentry translate="no" props="quantity">1</stentry>
            <stentry translate="yes" props="comment">Another comment</stentry>
         </strow>
      </simpletable>
   </refbody>
</reference>

<强>解释

查找文档中的有用strow元素由复合键标识,复合键由两部分组成:部件号和组名。因此,这两个值都必须参与use=的{​​{1}}属性,以便识别所需的<xsl:key>

答案 1 :(得分:1)

  

要手动执行此操作,我需要查看XML以获取特定内容   部分组(例如,A组部分)

如果你的意思是title元素中出现的部分组(在XML文档的部分中,你到目前为止还没有向我们展示过),那么你需要在XSLT样式表中进行两处更改。 :

1.将密钥定义更改为:

<xsl:key name="part-number" match="strow" use="concat(stentry[@props='part-section'], '|', stentry[@props='part-number'])" />

2.将$ matching-part变量的定义更改为:

<xsl:variable name="matching-part" select="key('part-number', concat(ancestor::reference/title, '|', ../stentry[@props='part-number']), document('pm_restrict_redo-2.xml'))" />