我如何使用 XSL 获得一组不同的 xml 节点值

how do i get a set of distinct xml node values using XSL

我有以下 XML 输入和所需的输出以及下面显示的内容。想法是在检测到 /Scripts/Script 节点和 /Scripts/Script/ 时设置 callLegSet 参数检测到 Preamble callLegSet 将包含当前 Script 元素的不同值集。我不确定这是否是考虑 xsl 的正确方法,我读到一个参数只能设置一次,所以这可能是一个问题;但如果是这样,列表如何接受新值?

谁能解释一下这是怎么回事,我该如何解决。


    <xsl:stylesheet version="1.0">
      <xsl:variable name="mode" select="1" />
    
      <xsl:key name="keyCallLeg" match="text()" use="." />
    
      <xsl:template match="Scripts/Script">
        <Script>
          <xsl:apply-templates>
            <xsl:with-param
              name="callLegSet"
              select="descendant::Command[(@command='10' or @command='11') and @mode='1']/Fields/Field[@name='type']/Value/text()
            [generate-id()=generate-id(key('keyCallLeg',.)[1])]">
            </xsl:with-param>
          </xsl:apply-templates>
        </Script>
      </xsl:template>
    
      <xsl:template match="Scripts/Script/Preamble">
        <xsl:param name="callLegSet"/>
        <Preamble>
          <pit>
            <xsl:for-each select="$callLegSet">
              <xsl:variable name="currElem" select="."/>
              <Field type="0" name="{$currElem}" mode="{$mode}"/>
            </xsl:for-each>
          </pit>
        </Preamble>
      </xsl:template>
    
      <xsl:template match="Commands"></xsl:template>
      <xsl:template match="Command"></xsl:template>
    
      <xsl:template match="*|@*|text()">
        <xsl:copy>
          <xsl:apply-templates select="*|@*|text()"/>
        </xsl:copy>
      </xsl:template>
    </xsl:stylesheet>

 

       <xml>
            <Scripts>
                <Script>
              <Preamble></Preamble>
                    <Commands>
                <Command mode="1" command="10">
                            <Fields>
                                <Field ordinal="11" name="type">
                                    <Value>Type_A</Value>
                                </Field>
                            </Fields>
                        </Command>
                <Command mode="1" command="11">
                            <Fields>
                                <Field ordinal="14" name="type">
                                    <Value>Type_A</Value>
                                </Field>
                            </Fields>
                        </Command>
                    </Commands>
                </Script>
                <Script>
              <Preamble></Preamble>
              <Commands>
                <Command mode="1" command="10">
                  <Fields>
                    <Field ordinal="11" name="type">
                      <Value>Type_A</Value>
                    </Field>
                  </Fields>
                </Command>
                <Command mode="1" command="11">
                  <Fields>
                    <Field ordinal="14" name="type">
                      <Value>Type_B</Value>
                    </Field>
                  </Fields>
                </Command>
                <Command mode="1" command="10">
                  <Fields>
                    <Field ordinal="11" name="type">
                      <Value>Type_A</Value>
                    </Field>
                  </Fields>
                </Command>
                        <Command mode="1" command="11">
                            <Fields>
                                <Field ordinal="14" name="type">
                                    <Value>Type_C</Value>
                                </Field>
                            </Fields>
                        </Command>
                    </Commands>
                </Script>
                <Script>
              <Preamble></Preamble>
              <Commands>
                <Command mode="1" command="10">
                  <Fields>
                    <Field ordinal="11" name="type">
                      <Value>Type_B</Value>
                    </Field>
                  </Fields>
                </Command>
                <Command mode="1" command="10">
                  <Fields>
                    <Field ordinal="11" name="type">
                      <Value>Type_Z</Value>
                    </Field>
                  </Fields>
                </Command>
              </Commands>
                </Script>
            </Scripts>
        </xml>


    <xml>
      <Scripts>
        <Script>
          <Preamble>
            <pit>
              <Field type="0" name="Type_A" mode="1" />
            </pit>
          </Preamble>
        </Script>
        <Script>
          <Preamble>
            <pit>
              <Field type="0" name="Type_B" mode="1" />
              <Field type="0" name="Type_C" mode="1" />
            </pit>
          </Preamble>
        </Script>
        <Script>
          <Preamble>
            <pit>
              <Field type="0" name="Type_Z" mode="1" />
            </pit>
          </Preamble>
        </Script>
      </Scripts>
    </xml>


    <xml>
      <Scripts>
        <Script>
          <Preamble>
            <pit>
              <Field type="0" name="Type_A" mode="1" />
            </pit>
          </Preamble>
        </Script>
        <Script>
          <Preamble>
            <pit>
              <Field type="0" name="Type_A" mode="1" />
              <Field type="0" name="Type_B" mode="1" />
              <Field type="0" name="Type_C" mode="1" />
            </pit>
          </Preamble>
        </Script>
        <Script>
          <Preamble>
            <pit>
              <Field type="0" name="Type_B" mode="1" />
              <Field type="0" name="Type_Z" mode="1" />
            </pit>
          </Preamble>
        </Script>
      </Scripts>
    </xml>

AFAICT,你想要的结果可以很简单地使用:

XSLT 1.0

<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="yes"/>

<xsl:key name="k1" match="Command" use="concat(Fields/Field/Value, '|', generate-id(..))" />

<xsl:template match="/xml">
    <xml>
        <Scripts>
            <xsl:for-each select="Scripts/Script">
                <Script>
                    <Preamble>
                        <pit>
                            <xsl:for-each select="Commands/Command[count(. | key('k1', concat(Fields/Field/Value, '|', generate-id(..)))[1]) = 1]">
                                <Field type="0" name="{Fields/Field/Value}" mode="1" />
                            </xsl:for-each>
                        </pit>
                    </Preamble>
                </Script>
            </xsl:for-each>
        </Scripts>
    </xml>
</xsl:template>

</xsl:stylesheet>

当然,在 XSLT 2.0 或更高版本中甚至更简单,或者使用支持 EXSLT set:distinct() 扩展功能的处理器。