Несколько строк с использованием XSLT - PullRequest
0 голосов
/ 04 июня 2018

Я ценю, если кто-нибудь может мне помочь в этом.У меня есть XML, который выглядит следующим образом:

<root>
<worker>
     <Primary_Key>12345</Primary_Key>
     <First_Name>ABC</First_Name>
     <Last_Name>DEF</Last_Name>         
    <Multiple_Data>
        <Code>MO</Code>
        <Amount>35</Amount>
    </Multiple_Data>
    <Multiple_Data>
        <Code>PA</Code>
        <Amount>45</Amount>
    </Multiple_Data>
</worker>
<worker>
    <Primary_Key>67890</Primary_Key>
    <First_Name>GHI</First_Name>
    <Last_Name>JKL</Last_Name>
    <Multiple_Data>
        <Code>PA</Code>
        <Amount>25</Amount>
    </Multiple_Data>
</worker>
<worker>
    <Primary_Key>11121</Primary_Key>
    <First_Name>MNO</First_Name>
    <Last_Name>PQR</Last_Name>    
</worker</root>

И мне нужно иметь вывод, который будет выглядеть точно так:

12345, ABC, DEF, MO, 35
12345, ABC, DEF, PA, 45
67890, GHI, JKL, PA, 25
11121, MNO, PQR ,,

12345 имеет несколько кодов данных и сумм,Значения отображаются в отдельных строках.11121 не имеет кода и суммы, поэтому отображается только разделитель ,,.

Вот XSLT, но, кажется, не работает:

<output method="text"/>

<variable name="delimiter"><text>,</text></variable>    
<variable name="linefeed" select="'&#xd;&#xa;'"/>
<template match="child::Primary_Key">     
    <choose>
        <when test="preceding-sibling::Multiple_Data//child::text() = ''">
            <for-each select="following-sibling::Multiple_Data">

                <value-of select="concat(preceding-sibling::Primary_Key/child::text(), $delimiter, preceding-sibling::First_Name/child::text(), $delimiter, preceding-sibling::Last_Name/child::text(), $delimiter, child::Code/child::text(), $delimiter, child::Amount/child::text())"/>

                <if test="(self::Primary_Key[position() = last()])">
                    <value-of select="$linefeed"/> 
                </if>

            </for-each>
        </when>
        <otherwise>
            <for-each select="child::Primary_Key">                    
                <value-of select="concat(preceding-sibling::Primary_Key/child::text(), $delimiter, preceding-sibling::First_Name/child::text(), $delimiter, preceding-sibling::Last_Name/child::text(), $delimiter, $delimiter )"/>                
                <if test="(self::Primary_Key[position() = last()])">
                    <value-of select="$linefeed"/> 
                </if>

            </for-each>

        </otherwise>

    </choose>                        
</template>
<template match="child::root/worker">
    <apply-templates select="child::Primary_Key"/>
</template>
</transform>

Когда я пытаюсь использовать это ниже XSLT, это дает мне ненужную новую строку вверху и пробелы.if (position ()> 1) не работает, чтобы избавиться от первой пустой строки в моем выводе.И, конечно же, работник, у которого нет нескольких данных, здесь не отображается.

<transform xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0">

<output method="text"/>

<variable name="delimiter"><text>,</text></variable>    
<variable name="linefeed" select="'&#xd;&#xa;'"/>
<template match="child::Primary_Key">     

       <for-each select="following-sibling::Multiple_Data">

                <value-of select="concat(preceding-sibling::Primary_Key/child::text(), $delimiter, preceding-sibling::First_Name/child::text(), $delimiter, preceding-sibling::Last_Name/child::text(), $delimiter, child::Code/child::text(), $delimiter, child::Amount/child::text())"/>                
                <if test="(self::Primary_Key[position() = last()])">
                    <value-of select="$linefeed"/> 
                </if>

            </for-each>

</template>
<template match="child::root/worker">
    <apply-templates select="child::Primary_Key"/>
</template>

Существуют ли другие способы кодирования этого кода без использования этого преобразования в заголовке?

<transform xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0">

Я хотел бы создать xslt, начинающийся с:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

, но выглядит как дочерний, предыдущий-брат и следующий-брат :: кодыне поддерживаются этим.

Большое спасибо за вашу помощь.

1 Ответ

0 голосов
/ 04 июня 2018

Учитывая, что вы можете использовать XSLT 2 и хотите иметь некоторый вывод для данных, которых нет во входной выборке, я бы предложил использовать двухступенчатое преобразование, где первый шаг в отдельном режиме просто добавляет пустые элементы для отсутствующихданные, а затем второй шаг в режиме по умолчанию выводит CSV.

Если вы можете использовать Saxon 9.8 (любой выпуск) или 9.7 PE / EE в oXygen и XSLT 3, вы можете легко настроить другой режим с помощью

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="3.0">

  <xsl:output method="text"/>

  <xsl:mode name="add-dummy-data" on-no-match="shallow-copy"/>

  <xsl:variable name="dummy-data">
      <xsl:apply-templates mode="add-dummy-data"/>
  </xsl:variable>

  <xsl:template match="worker[not(Multiple_Data)]" mode="add-dummy-data">
      <xsl:copy>
          <xsl:copy-of select="@*, node()"/>
          <Multiple_Data>
              <Code/>
              <Amount/>
          </Multiple_Data>
      </xsl:copy>
  </xsl:template>

  <xsl:template match="/">
    <xsl:apply-templates select="$dummy-data/root/worker/Multiple_Data"/>
  </xsl:template>

  <xsl:template match="Multiple_Data">
      <xsl:value-of select="../Primary_Key, ../First_Name, ../Last_Name, Code, Amount" separator=","/>
      <xsl:text>&#10;</xsl:text>
  </xsl:template>

</xsl:stylesheet>

см. https://xsltfiddle.liberty -development.net / bdxtq1 / 1

, если вы привязаны к XSLT 2, вам нужно использовать

<xsl:template match="@* | node()" mode="add-dummy-data">
  <xsl:copy>
    <xsl:apply-templates select="@* | node()" mode="#current"/>
  </xsl:copy>
</xsl:template>

вместо <xsl:mode name="add-dummy-data" on-no-match="shallow-copy"/>

...