xslt 中的 For-Each 问题

Issue with For-Each in xslt

鉴于 xml:

<?xml version="1.0" encoding="UTF-8"?>
<Envelope>
  <Interchange>
    <Group>
      <Message>
        <Loop2000>
          <Loop2300>
            <K3>
              <F449>BlaBlaBla</F449>
            </K3> 
            <K3>
              <F449>IEHPTraceID_123456</F449>
            </K3>
          </Loop2300>
        </Loop2000>
      </Message>
    </Group>
  </Interchange>
</Envelope>

和以下 xslt:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
        <xsl:output method="xml" indent="yes" />
        <xsl:template match="/">
                <xsl:for-each select="Envelope/Interchange/Group/Message/Loop2000/Loop2300/K3">
                    <xsl:if test="substring(/Envelope/Interchange/Group/Message/Loop2000/Loop2300/K3/F449,1,11)='IEHPTraceID'">
                        <InboundDataXml>
                            <CustomAttributes>
                                 <CustomAttribute>
                                    <AttributeName>Trace Id</AttributeName>
                                    <AttributeValue><xsl:value-of select="/Envelope/Interchange/Group/Message/Loop2000/Loop2300/K3/F449" /></AttributeValue>
                                 </CustomAttribute>
                            </CustomAttributes>
                        </InboundDataXml>
                    </xsl:if>
                </xsl:for-each>
        </xsl:template>
</xsl:transform>

我期待的结果是:

<InboundDataXml>
   <CustomAttributes>
      <CustomAttribute>
         <AttributeName>Trace Id</AttributeName>
         <AttributeValue>IEHPTraceID_123456</AttributeValue>
      </CustomAttribute>
   </CustomAttributes>
</InboundDataXml>

显然我的 for-each 有问题,因为我假设它会看到正确的节点并输出预期的结果,但那并没有发生。如果我删除第一个节点,我会得到预期的结果。有人可以引导我朝着正确的方向前进吗

请尝试以下 XSLT。

xsl:for-each循环中,上下文是K3元素的所有子节点。无需在 XPath 表达式中再次从根开始。

XSLT

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/">
        <xsl:for-each select="Envelope/Interchange/Group/Message/Loop2000/Loop2300/K3">
            <xsl:if test="substring(F449,1,11)='IEHPTraceID'">
                <InboundDataXml>
                    <CustomAttributes>
                        <CustomAttribute>
                            <AttributeName>Trace Id</AttributeName>
                            <AttributeValue>
                                <xsl:value-of select="F449"/>
                            </AttributeValue>
                        </CustomAttribute>
                    </CustomAttributes>
                </InboundDataXml>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

输出

<?xml version='1.0' ?>
<InboundDataXml>
  <CustomAttributes>
    <CustomAttribute>
      <AttributeName>Trace Id</AttributeName>
      <AttributeValue>IEHPTraceID_123456</AttributeValue>
    </CustomAttribute>
  </CustomAttributes>
</InboundDataXml>

使用时使用 xsl:for - 每个上下文都会更改为所选元素。所以在循环内部,上下文是 K3 和 child-element F449。所以你可以像这样直接测试 child:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes" />
  <xsl:template match="/">
    <xsl:for-each select="Envelope/Interchange/Group/Message/Loop2000/Loop2300/K3">
      <xsl:if test="substring(F449,1,11)='IEHPTraceID'">
        <InboundDataXml>
          <CustomAttributes>
            <CustomAttribute>
              <AttributeName>Trace Id</AttributeName>
              <AttributeValue><xsl:value-of select="F449" /></AttributeValue>
            </CustomAttribute>
          </CustomAttributes>
        </InboundDataXml>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>
</xsl:transform>

您可以通过使用谓词而不使用 xsl:if 来获得相同的效果,如下所示:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes" />
  <xsl:template match="/">
    <xsl:for-each select="Envelope/Interchange/Group/Message/Loop2000/Loop2300/K3[substring(F449,1,11)='IEHPTraceID']">
      <InboundDataXml>
        <CustomAttributes>
          <CustomAttribute>
            <AttributeName>Trace Id</AttributeName>
            <AttributeValue><xsl:value-of select="F449" /></AttributeValue>
          </CustomAttribute>
        </CustomAttributes>
      </InboundDataXml>
    </xsl:for-each>
  </xsl:template>
</xsl:transform>

作为 xsl:foreach 的替代方案,您也可以这样做:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes" />
  
  <xsl:template match="K3"/>
    
  <xsl:template match="K3[substring(F449,1,11)='IEHPTraceID']">
    <InboundDataXml>
      <CustomAttributes>
        <CustomAttribute>
          <AttributeName>Trace Id</AttributeName>
          <AttributeValue><xsl:value-of select="F449" /></AttributeValue>
        </CustomAttribute>
      </CustomAttributes>
    </InboundDataXml>
  </xsl:template>
</xsl:transform>