XSL通过拆分元素

时间:2018-05-31 11:14:20

标签: xslt-1.0

我有以下XML,其中包含单个元素中的订单详细信息。

<?xml version="1.0" encoding="UTF-8"?>
<MESSAGE xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <MESSAGE_ID>361155</MESSAGE_ID>
    <NAME>Header123</NAME>
    <HEADERS>
        <HEADER>
            <ACTION_COUNT>1</ACTION_COUNT>
            <ACTION_DESC>
                <DAILY_LOAD>
                    <LOAD_NO>1</LOAD_NO>
                    <CUSTOMER_NO>09656951</CUSTOMER_NO>
                    <REFERENCE xsi:nil="1"/>
                    <SERIAL>450255470000403803</SERIAL>
                    <ORDERS>
                        <ORDER>
                            <ITEM>5000128762885</ITEM>
                            <DETAILS>4582;Robert and Co;8;5526;SWD</DETAILS>
                            <EMP_NO>13</EMP_NO>
                            <USE_BY_DATE>20110611</USE_BY_DATE>
                            <DEPOT>5000128910035</DEPOT>
                        </ORDER>
                        <ORDER>
                            <ITEM>5000128853613</ITEM>
                            <DETAILS>5000;Anne and Co;9;2020;ATM</DETAILS>
                            <EMP_NO>5</EMP_NO>
                            <USE_BY_DATE>20110613</USE_BY_DATE>
                            <DEPOT>5000128910035</DEPOT>
                        </ORDER>
                    </ORDERS>
                </DAILY_LOAD>
            </ACTION_DESC>
        </HEADER>
    </HEADERS>
    <LIST_ID>23689</LIST_ID>
    <TRAILER>TEST_NEEDED</TRAILER>
</MESSAGE>

我需要将其转换为以下格式。 (只有DAILY_LOAD&gt; ORDERS部分应更改如下)

.....
     <ORDERS>
        <ORDER>
            <ITEM>5000128762885</ITEM>
            <ORDER_NO>4582</ORDER_NO>
            <CUSTOMER>Robert and Co</CUSTOMER>
            <NO_OF_ITEMS>8</NO_OF_ITEMS>
            <TOTAL>5526</TOTAL>
            <LOCATION>SWD</LOCATION>
            <EMP_NO>13</EMP_NO>
            <USE_BY_DATE>20110611</USE_BY_DATE>
            <DEPOT>5000128910035</DEPOT>
        </ORDER>
        <ORDER>
            <ITEM>5000128853613</ITEM>
            <ORDER_NO>5000</ORDER_NO>
            <CUSTOMER>Anne and Co</CUSTOMER>
            <NO_OF_ITEMS>9</NO_OF_ITEMS>
            <TOTAL>2020</TOTAL>
            <LOCATION>ATM</LOCATION>
            <EMP_NO>5</EMP_NO>
            <USE_BY_DATE>20110613</USE_BY_DATE>
            <DEPOT>5000128910035</DEPOT>
        </ORDER>
    </ORDERS>
.....

转换后的XML包含no,但它分为CUSTOMER,NO_OF_ITEMS,TOTAL和LOCATION。任何建议或帮助将受到高度赞赏。 提前谢谢。

1 个答案:

答案 0 :(得分:1)

XSLT 1.0

使用Heber.it博客中建议的 tokenizeString 模板。我根据递归级别(ORDER_NO,CUSTOMER,NO_OF_ITEMS等)修改了生成不同标记名称的代码。

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:template match="/">
    <xsl:apply-templates/>
  </xsl:template>

  <!-- replaces order nodes -->
  <xsl:template match="ORDER">
    <ORDER>
      <xsl:call-template name="tokenizeString">
        <xsl:with-param name="list" select="./DETAILS"/>
        <xsl:with-param name="delimiter" select="';'"/>
        <xsl:with-param name="level" select="1"/>
      </xsl:call-template> 
    </ORDER>
  </xsl:template>

  <!-- copy everything that doesn't match another template -->
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- template to tokenize strings -->
  <xsl:template name="tokenizeString">
    <!--passed template parameter -->
    <xsl:param name="list"/>
    <xsl:param name="delimiter"/>
    <xsl:param name="level"/>
    <xsl:choose>
      <xsl:when test="contains($list, $delimiter)">
        <xsl:choose>
          <xsl:when test="$level = 1">
            <ITEM>
              <xsl:value-of select="ITEM"/>
            </ITEM>
            <ORDER_NO>
              <xsl:value-of select="substring-before($list,$delimiter)"/>
            </ORDER_NO>
          </xsl:when>
          <xsl:when test="$level = 2">
            <CUSTOMER>
              <xsl:value-of select="substring-before($list,$delimiter)"/>
            </CUSTOMER>
          </xsl:when>
          <xsl:when test="$level = 3">
            <NO_OF_ITEMS>
              <xsl:value-of select="substring-before($list,$delimiter)"/>
            </NO_OF_ITEMS>
          </xsl:when>
          <xsl:when test="$level = 4">
            <TOTAL>
              <xsl:value-of select="substring-before($list,$delimiter)"/>
            </TOTAL>
          </xsl:when>
        </xsl:choose>
        <xsl:call-template name="tokenizeString">
          <!-- store anything left in another variable -->
          <xsl:with-param name="list" select="substring-after($list,$delimiter)"/>
          <xsl:with-param name="delimiter" select="$delimiter"/>
          <xsl:with-param name="level" select="$level + 1"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:choose>
          <xsl:when test="$list = ''">
            <xsl:text/>
          </xsl:when>
          <xsl:otherwise>
            <LOCATION>
              <xsl:value-of select="$list"/>
            </LOCATION>
            <EMP_NO>
              <xsl:value-of select="EMP_NO"/>
            </EMP_NO>
            <USE_BY_DATE>
              <xsl:value-of select="USE_BY_DATE"/>
            </USE_BY_DATE>
            <DEPOT>
              <xsl:value-of select="DEPOT"/>
            </DEPOT>            
          </xsl:otherwise>
        </xsl:choose>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

XSLT 2.0

使用tokenize功能可以执行此操作:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:template match="/">
    <xsl:apply-templates/>
  </xsl:template>
  <!-- this template replaces order nodes -->
  <xsl:template match="ORDER">
    <ORDER>
      <xsl:variable name="fields" select="tokenize(DETAILS, ';')"/>
      <ITEM>
        <xsl:value-of select="ITEM"/>
      </ITEM>
      <ORDER_NO>
        <xsl:value-of select="$fields[position()=1]"/>
      </ORDER_NO>
      <CUSTOMER>
        <xsl:value-of select="$fields[position()=2]"/>
      </CUSTOMER>
      <NO_OF_ITEMS>
        <xsl:value-of select="$fields[position()=3]"/>
      </NO_OF_ITEMS>
      <TOTAL>
        <xsl:value-of select="$fields[position()=4]"/>
      </TOTAL>
      <LOCATION>
        <xsl:value-of select="$fields[position()=5]"/>
      </LOCATION>
      <EMP_NO>
        <xsl:value-of select="EMP_NO"/>
      </EMP_NO>
      <USE_BY_DATE>
        <xsl:value-of select="USE_BY_DATE"/>
      </USE_BY_DATE>
      <DEPOT>
        <xsl:value-of select="DEPOT"/>
      </DEPOT>
    </ORDER>
  </xsl:template>
  <!-- this template copies everything that doesn't match another template -->
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>