4

我正在尝试使用 XSLT 中的“键”函数来提取一个值并将其添加到 XML 中的特定位置。但我没有做对。下面是输入和 XSLT。

请帮忙。

输入 XML:

<input  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xsi:noNamespaceSchemaLocation="nbA2.8.90.xsd">
            <info>User Info </info>
            <team>User Team </team>
            <nodeA id="test">
                <inodeAA> Sample </inodeAA>
                <inodeAB> Samples </inodeAB>
            </nodeA>
            <nodeA id="test2">
                <inodeAA> Sample </inodeAA>
                <inodeAB> Samples </inodeAB>
            </nodeA>
            <ns3:output xmlns:ns3="http://mysample.org">
                <ns3:reply id="test">
                    <ns3:pkey>55555</ns3:pkey>
                    <ns3:place>SampleLoc</ns3:place>
                </ns3:reply>
                <ns3:reply id="test2">
                    <ns3:pkey>55557</ns3:pkey>
                    <ns3:place>SampleLoc2</ns3:place>
                </ns3:reply>
            </ns3:output>
        </input>

预期输出:

<input xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xsi:noNamespaceSchemaLocation="nbA2.8.90.xsd">
        <info>User Info </info>
        <team>User Team </team>
        <nodeA id="test">
            <inodeAA> Sample </inodeAA>
            <pkey>55555</pkey>
            <inodeAB> Samples </inodeAB>
        </nodeA>
        <nodeA id="test2">
            <inodeAA> Sample </inodeAA>
            <pkey>55557</pkey>
            <inodeAB> Samples </inodeAB>
        </nodeA>            
    </input>

下面是我的 XSL:

    <xsl:stylesheet version="2.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:ns3="http://mysample.org"
        exclude-result-prefixes="soap xsl">
        <xsl:output omit-xml-declaration="no" indent="yes" />

        <xsl:key name="parKey" match="ns3:output/ns3:reply/ns3:pkey" use="/input/ns3:output/ns3:reply/@id"></xsl:key>

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

        <xsl:template match="/input">
            <xsl:variable name="output_186" select="ns3:output"/>
            <xsl:copy>
                <xsl:copy-of copy-namespaces="no" select="./@*" />
                <xsl:copy-of select=" * except $output_186"></xsl:copy-of>
            </xsl:copy> 
        </xsl:template>

        <xsl:template match="/input//nodeA">
            <xsl:copy>
                <xsl:copy-of copy-namespaces="no" select="./@*" />
                <pkey>
                    <xsl:copy-of select="key('parKey', @id)|." />           
                </pkey>                 
                <xsl:copy-of copy-namespaces="no" select="node()" />
            </xsl:copy>             
        </xsl:template> 
    </xsl:stylesheet>

输出如下:未显示我的必填字段

    <input xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"        
        xsi:noNamespaceSchemaLocation="nbA2.8.90.xsd" >
        <info>User Info </info>
        <team>User Team </team>
        <nodeA id="test">
            <inodeAA> Sample </inodeAA>
            <inodeAB> Samples </inodeAB>
        </nodeA>
        <nodeA id="test2">
            <inodeAA> Sample </inodeAA>
            <inodeAB> Samples </inodeAB>
        </nodeA>
    </input>

请帮助我我到底在哪里失踪。

谢谢...

4

3 回答 3

1

最明显的错误是 xsl:key 中的“使用”表达式。这应该始终是一个相对路径表达式,相对于“匹配”模式匹配的节点。我还没有弄清楚它应该是什么,因为我还没有真正弄清楚你想要做什么。但我怀疑它应该是

match="ns3:reply" use="@id"
于 2012-12-14T17:07:01.507 回答
1

use属性xsl:key是相对于被匹配元素的路径,因此您可能想要

<xsl:key name="parKey" match="ns3:pkey" use="../@id"/>

以便按其父元素pkey的属性对元素进行分组。idreply

但更一般地说,您的/input模板是可疑的:

    <xsl:template match="/input">
        <xsl:variable name="output_186" select="ns3:output"/>
        <xsl:copy>
            <xsl:copy-of copy-namespaces="no" select="./@*" />
            <xsl:copy-of select=" * except $output_186"></xsl:copy-of>
        </xsl:copy> 
    </xsl:template>

这只是复制整个源input元素(减去ns3:output),它不是递归应用模板,因此nodeA处理 的模板pkey永远不会触发。

尝试更多类似的东西:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:ns3="http://mysample.org"
    exclude-result-prefixes="xsl">
    <xsl:strip-space elements="*" />
    <xsl:output omit-xml-declaration="no" indent="yes" />

    <xsl:key name="parKey" match="ns3:pkey" use="../@id"/>

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

    <!-- except ns3:output -->
    <xsl:template match="ns3:output" />

    <xsl:template match="nodeA">
        <xsl:copy copy-namespaces="no">
            <xsl:apply-templates select="@*|node()" />
            <xsl:element name="pkey">
                <xsl:value-of select="key('parKey', @id)" />
            </xsl:element>
        </xsl:copy>             
    </xsl:template> 
</xsl:stylesheet>
于 2012-12-14T17:07:09.663 回答
1

更短的解决方案

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ns3="http://mysample.org">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>
 <xsl:key name="kpKeyByParentId" match="ns3:pkey" use="../@id"/>

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

 <xsl:template match="inodeAA">
  <xsl:call-template name="identity"/>
  <xsl:apply-templates select="key('kpKeyByParentId', ../@id)"/>
 </xsl:template>

 <xsl:template match="ns3:pkey">
   <xsl:element name="{local-name()}">
    <xsl:apply-templates/>
   </xsl:element>
 </xsl:template>
 <xsl:template match="ns3:output"/>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时:

<input  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xsi:noNamespaceSchemaLocation="nbA2.8.90.xsd">
    <info>User Info </info>
    <team>User Team </team>
    <nodeA id="test">
        <inodeAA> Sample </inodeAA>
        <inodeAB> Samples </inodeAB>
    </nodeA>
    <nodeA id="test2">
        <inodeAA> Sample </inodeAA>
        <inodeAB> Samples </inodeAB>
    </nodeA>
    <ns3:output xmlns:ns3="http://mysample.org">
        <ns3:reply id="test">
            <ns3:pkey>55555</ns3:pkey>
            <ns3:place>SampleLoc</ns3:place>
        </ns3:reply>
        <ns3:reply id="test2">
            <ns3:pkey>55557</ns3:pkey>
            <ns3:place>SampleLoc2</ns3:place>
        </ns3:reply>
    </ns3:output>
</input>

产生了想要的正确结果:

<input xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:noNamespaceSchemaLocation="nbA2.8.90.xsd">
   <info>User Info </info>
   <team>User Team </team>
   <nodeA id="test">
      <inodeAA> Sample </inodeAA>
      <pkey>55555</pkey>
      <inodeAB> Samples </inodeAB>
   </nodeA>
   <nodeA id="test2">
      <inodeAA> Sample </inodeAA>
      <pkey>55557</pkey>
      <inodeAB> Samples </inodeAB>
   </nodeA>
</input>

说明

  1. 身份规则“按原样”复制选择执行的每个节点。

  2. 匹配 an 的 ovveriding 模板inodeAA调用标识模板来复制自身,然后将模板应用于任何ns3:pkey元素,其父属性的值与此父属性的id值相同。为了方便和高效,这是通过调用引用键的函数来完成的,该键将 an 定义为其父属性的函数。idinodeAAkey()"kpKeyByParentId"ns3:pkeyid

  3. 匹配元素的模板ns3:pkey会创建一个元素(在无命名空间中),其名称是匹配元素的本地名称,并且还会复制其内容。

  4. 元素ns3:output及其整个子树被具有空主体的匹配模板排除在处理之外(“删除”)。

于 2012-12-14T18:54:27.073 回答