XSLT Обрабатывать пустые ячейки для CSV, если тег не существует - PullRequest
0 голосов
/ 01 апреля 2020

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

Пример: XML Input

<rootElm>
   <entry>
      <col1>text</col1>
      <col2>text</col2>
      <col3>text</col3>
      <colX>text</colX>
   </entry>
   <entry>
      <col1>text</col1>
      <col3>text</col3>
      <colX>text</colX>
   </entry>
   <entry>
      <col1>text</col1>
      <col2>text</col2>
      <colX>text</colX>
   </entry>
</rootElm>

XSL:

<xsl:template match="entry">
    <xsl:choose>
        <xsl:when test="col1">
            <xsl:apply-templates select="col1"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:text> ,</xsl:text> <!-- comma separator to output empty cell if tag not exist -->
        </xsl:otherwise>
    </xsl:choose>

        <xsl:when test="col2">
            <xsl:apply-templates select="col2"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:text> ,</xsl:text>
        </xsl:otherwise>
    </xsl:choose>

        <xsl:when test="col3">
            <xsl:apply-templates select="col3"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:text> ,</xsl:text> 
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

Приведенный выше код работает хорошо и дает желаемый результат, но я пытаюсь найти более простое решение, например l oop, через Нужны имена заголовков (col1, col2, col3) и проверьте, существует ли тег с указанным именем в элементе "entry", а затем примените к нему шаблоны, в противном случае выведите разделитель CSV ",". Может ли это быть достигнуто с помощью XSLT?

Выход CSV:

text,text,text
text,,text //col2 doesn't exist for the second entry
text,text, //col3 doesn't exist for the third entry

1 Ответ

1 голос
/ 02 апреля 2020

Попробуйте что-то вроде:

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8"/>

<xsl:template match="/rootElm">
    <xsl:variable name="col" select="distinct-values(entry/*/name())"/>
    <xsl:for-each select="entry">
        <xsl:variable name="entry" select="."/>
        <xsl:for-each select="$col">
            <xsl:value-of select="$entry/*[name()=current()]"/>
            <xsl:value-of select="if(position()!=last()) then',' else '&#10;'"/>
        </xsl:for-each>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

Демо: https://xsltfiddle.liberty-development.net/naZXVEQ/1


Добавлено:

как мне указать, что я хочу отображать только col1, col2 и col3. Я не хочу отображать colX или любые другие столбцы, которые могут существовать.

Просто измените определение переменной $col на

<xsl:variable name="col" select="('col1', 'col2', 'col3')"/> 

Или еще проще:

<xsl:template match="/rootElm">
    <xsl:for-each select="entry">
        <xsl:value-of select="string(col1), string(col2), string(col3)" separator=","/>
        <xsl:text>&#10;</xsl:text> 
    </xsl:for-each>
</xsl:template>
...