首页 > 解决方案 > 第一个节点上模板内的数据“数组”的 XSL 模板

问题描述

这是我的 Stackoverflow 帖子 Matching templates with different configuration on the same node的延续,正如我在原始帖子Nesting xsl templates and references multiple templates to the same node?

如何在第一个 ROW 标记上实现模板,这很可能是源 XML 中唯一的 ROW 标记?我的问题涉及 ROW 标记中的最后一个节点,在源 XML 的标记名中包含 E1EDL44:

<?xml version="1.0" encoding="UTF-8"?>
<FMPDSORESULT xmlns="http://www.filemaker.com/fmpdsoresult">
    <ROW>
        <EDI_DC40.TABNAM><DATA>EDI_DC40</DATA></EDI_DC40.TABNAM>
        <E1EDL20.VBELN><DATA>649758</DATA></E1EDL20.VBELN>
        <E1EDL18.QUALF><DATA>ORI</DATA></E1EDL18.QUALF>
        <E1EDL24.POSNR>000001</E1EDL24.POSNR>
        <E1EDL41.QUALI>001</E1EDL41.QUALI>
        <E1EDL37.EXIDV><DATA>5650327422</DATA></E1EDL37.EXIDV>
        <!-- These E1EDL44 lines will appear the same on every ROW, in case there is more than one ROW-->
        <!-- There are more tags, actually, left out for simplicity-->
        <E1EDL44.VELIN>
             <DATA>1</DATA>
             <DATA>2</DATA>
             <DATA>3</DATA>
        </E1EDL44.VELIN>
        <E1EDL44.POSNR>
             <DATA>000001</DATA>
             <DATA>000123</DATA>
             <DATA>456789</DATA>
        </E1EDL44.POSNR>
    </ROW>
    <ROW>
        <EDI_DC40.TABNAM><DATA>EDI_DC40</DATA></EDI_DC40.TABNAM>
        <E1EDL20.VBELN><DATA>649758</DATA></E1EDL20.VBELN>
        <E1EDL18.QUALF><DATA>ORI</DATA></E1EDL18.QUALF>
        <E1EDL24.POSNR>2</E1EDL24.POSNR>
        <E1EDL41.QUALI>002</E1EDL41.QUALI>
        <E1EDL37.EXIDV><DATA>5650327422</DATA></E1EDL37.EXIDV>
        <E1EDL44.VELIN>
             <DATA>1</DATA>
             <DATA>2</DATA>
             <DATA>3</DATA>
        </E1EDL44.VELIN>
        <E1EDL44.POSNR>
             <DATA>000001</DATA>
             <DATA>000123</DATA>
             <DATA>456789</DATA>
        </E1EDL44.POSNR>
    </ROW>
</FMPDSORESULT>

结果必须是:

<?xml version="1.0" encoding="utf-16"?>
<DELVRY05>
  <IDOC BEGIN="1">
    <EDI_DC40 SEGMENT="1">
      <TABNAM>EDI_DC40</TABNAM>
    </EDI_DC40>
    <E1EDL20 SEGMENT="1">
      <VBELN>649758</VBELN>
      <E1EDL18 SEGMENT="1">
        <QUALF>ORI</QUALF>
      </E1EDL18>
      <E1EDL24 SEGMENT="1">
        <POSNR>000001</POSNR>
        <E1EDL41 SEGMENT="1">
          <QUALI>001</QUALI>
        </E1EDL41>
      </E1EDL24>
      <E1EDL24 SEGMENT="1">
        <POSNR>2</POSNR>
        <E1EDL41 SEGMENT="1">
          <QUALI>002</QUALI>
        </E1EDL41>
      </E1EDL24>
    </E1EDL20>
      <E1EDL37 SEGMENT="1">
        <EXIDV>5650327422</EXIDV>
        <E1EDL44 SEGMENT="1">
          <VELIN>1</VELIN>
          <POSNR>000001</POSNR>
        </E1EDL44>
        <E1EDL44 SEGMENT="1">
          <VELIN>2</VELIN>
          <POSNR>000123</POSNR>
        </E1EDL44>
        <E1EDL44 SEGMENT="1">
          <VELIN>3</VELIN>
          <POSNR>456789</POSNR>
        </E1EDL44>
      </E1EDL37>
  </IDOC>
</DELVRY05>

在 Sebastien 的帮助下(参见前面提到的帖子),我对 xslt 的看法如下:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:fm="http://www.filemaker.com/fmpdsoresult"
    exclude-result-prefixes="fm"
    version="1.0">

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

  <xsl:template match="/">
    <DELVRY05>
      <xsl:apply-templates select="fm:FMPDSORESULT/fm:ROW[1]"/>
    </DELVRY05>
  </xsl:template>
  
  <xsl:template match="fm:ROW">
    <IDOC BEGIN="1">
      <EDI_DC40 SEGMENT="1">
        <TABNAM><xsl:value-of select="fm:EDI_DC40.TABNAM/fm:DATA"/></TABNAM>
      </EDI_DC40>
      <E1EDL20 SEGMENT="1">
        <VBELN><xsl:value-of select="fm:E1EDL20.VBELN/fm:DATA"/></VBELN>
        <E1EDL18 SEGMENT="1"><QUALF><xsl:value-of select="fm:E1EDL18.QUALF/fm:DATA"/></QUALF></E1EDL18>
        
        <!-- Use template for elements that are present mutltiple times. -->
        <xsl:apply-templates select="../fm:ROW/fm:E1EDL24.POSNR"/>
        <E1EDL37 SEGMENT="1">
          <EXIDV><xsl:value-of select="fm:E1EDL37.EXIDV/fm:DATA"/></EXIDV>
          <VHILM><xsl:value-of select="fm:E1EDL37.VHILM/fm:DATA"/></VHILM>
          <EXIDV2><xsl:value-of select="fm:E1EDL37.EXIDV2/fm:DATA"/></EXIDV2>
          <EXIDA><xsl:value-of select="fm:E1EDL37.EXIDA/fm:DATA"/></EXIDA>
          <xsl:apply-templates select="fm:E1EDL44.VELIN/fm:DATA"/>
        </E1EDL37>
      </E1EDL20>
    </IDOC>
  </xsl:template>
  
  <xsl:template match="fm:E1EDL24.POSNR">
    <E1EDL24 SEGMENT="1">
      <POSNR><xsl:value-of select="."/></POSNR>
      <E1EDL41 SEGMENT="1">
        <QUALI><xsl:value-of select="../fm:E1EDL41.QUALI"/></QUALI>
      </E1EDL41>
    </E1EDL24>
  </xsl:template>

  <xsl:template match="fm:E1EDL44.VELIN/fm:DATA">
    <E1EDL44 SEGMENT="1">
      <VELIN><xsl:value-of select="."/></VELIN>
      <POSNR><xsl:value-of select="../../fm:E1EDL44.POSNR/fm:DATA"/></POSNR>
    </E1EDL44>
  </xsl:template>
  
</xsl:stylesheet>

这适用于 VELIN,但不适用于 POSNR,它总是显示第一个 DATA 标签数据:

      <E1EDL37 SEGMENT="1">
        <EXIDV>5650327422</EXIDV>
        <E1EDL44 SEGMENT="1">
          <VELIN>1</VELIN>
          <POSNR>000001</POSNR>
        </E1EDL44>
        <E1EDL44 SEGMENT="1">
          <VELIN>1</VELIN>
          <POSNR>000001</POSNR>
        </E1EDL44>
        <E1EDL44 SEGMENT="1">
          <VELIN>3</VELIN>
          <POSNR>000001</POSNR>
        </E1EDL44>
      </E1EDL37>

如何修复我的模板?

标签: xmlxslt

解决方案


我认为您可以使用<POSNR><xsl:value-of select="../../fm:E1EDL44.POSNR/fm:DATA[position() = current()]"/></POSNR>. 这假设匹配的元素确实包含 values 1,2,3,4,..,就像您的示例数据一样。

否则存储

 <xsl:variable name="pos" select="position()"/>

并使用<POSNR><xsl:value-of select="../../fm:E1EDL44.POSNR/fm:DATA[$pos]"/></POSNR>


推荐阅读