【问题标题】:Create key within xslt template在 xslt 模板中创建密钥
【发布时间】:2016-12-11 06:46:17
【问题描述】:

我想将 XML 文件转换为 CSV 文件。我要导出的字段是<issues>。每个问题都有一组标准字段和一些自定义字段。可能的自定义字段在<issue-custom-fields> 中定义。并非每个 <issue> 都设置了所有自定义字段。对于 CSV 导出,我必须为每个缺失的条目添加一个空字段 (",,")。我该怎么做?

以下 xslt 文件循环遍历所有问题字段和所有自定义字段。而不是“字段值?”我想在当前项目中查找相应的字段值(如果存在,则为空白)。

XSLT 版本应该是 1.0。

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

    <xsl:output method="text" />

    <xsl:template match="/">
        <xsl:apply-templates select="xml_data/issues"/>
    </xsl:template>

    <xsl:template match="issue">
        <xsl:for-each select="*">
            <xsl:choose>
                <xsl:when test="name(.) = 'custom-values'">
                    <xsl:for-each select="/xml_data/issue-custom-fields/issue-custom-field">                                
                        <xsl:variable name="f" select="id" />

                        <xsl:text>field value?</xsl:text>

                        <xsl:if test="position() != last()">
                            <xsl:text>,</xsl:text>
                        </xsl:if>
                    </xsl:for-each>
                </xsl:when>

                <xsl:otherwise>
                    <xsl:value-of select="."/>          
                    <xsl:if test="position() != last()">
                        <xsl:text>,</xsl:text>
                    </xsl:if>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>         
    </xsl:template>
</xsl:transform>

作用于以下数据:

<?xml version="1.0" encoding="UTF-8"?>
    <xml_data>
        <projects type="array">
            <project>
                <id type="integer">10</id>
                <name>Helpdesk</name>
                <type>open</type>
            </project>
            <project>
                <id type="integer">20</id>
                <name>Development</name>
                <type>closed</type>
            </project>
        </projects>

        <issue-custom-fields>
            <issue-custom-field>
                <id>1000</id>
                <name>Delay</name>
            </issue-custom-field>
            <issue-custom-field>
                <id>1001</id>
                <name>Means of Delivery</name>
            </issue-custom-field>
            <issue-custom-field>
                <id>1002</id>
                <name>Shipping Date</name>
            </issue-custom-field>
        </issue-custom-fields>

        <issues type="array">
            <issue>
                <id type="integer">100</id>
                <project-id type="integer">10</project-id>
                <subject>first helpdesk issue</subject>
                <description>a small problem</description>
                <custom-values>
                    <custom-value>
                        <custom-field-id>1000</custom-field-id>
                        <value>15</value>
                    </custom-value>
                    <custom-value>
                        <custom-field-id>1002</custom-field-id>
                        <value>2016-08-01</value>
                    </custom-value>
                </custom-values>
            </issue>
            <issue>
                <id type="integer">101</id>
                <project-id type="integer">10</project-id>
                <subject>second helpdesk issue</subject>
                <description>a medium problem</description>
                <custom-values>
                    <custom-value>
                        <custom-field-id>1000</custom-field-id>
                        <value>10</value>
                    </custom-value>
                    <custom-value>
                        <custom-field-id>1001</custom-field-id>
                        <value>FTP</value>
                    </custom-value>
                </custom-values>
            </issue>
            <issue>
                <id type="integer">102</id>
                <project-id type="integer">10</project-id>
                <subject>third helpdesk issue</subject>
                <description>a huge security problem</description>
                <custom-values>
                    <custom-value>
                        <custom-field-id>1001</custom-field-id>
                        <value>SSH</value>
                    </custom-value>
                </custom-values>
            </issue>
            <issue>
                <id type="integer">103</id>
                <project-id type="integer">20</project-id>
                <subject>first "development" issue</subject>
                <description>just some "strange" software</description>
                <custom-values>
                </custom-values>
            </issue>
        </issues>
    </xml_data>

非常感谢您的帮助。

【问题讨论】:

  • 在文本中编写 XML 标记时,您必须将它们括在反引号 (`) 中,以使它们格式化为代码并且不会被 HTML 清理程序删除。我帮你修好了。
  • 请显示从样本输入产生的期望输出。还要告诉我们这是 XSLT 1 还是 2。

标签: xml csv xslt xslt-1.0


【解决方案1】:

如果我理解正确,你想这样做:

XSLT 1.0

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

<xsl:key name="custom-value" match="custom-value" use="concat(custom-field-id, '|', ancestor::issue/id)" />

<xsl:template match="/xml_data">
    <xsl:variable name="custom-fields" select="issue-custom-fields/issue-custom-field" />
    <!-- header -->
    <!-- standard fields -->
    <xsl:for-each select="issues/issue[1]/*[not(self::custom-values)]">
        <xsl:value-of select="name()"/>          
        <xsl:text>,</xsl:text>
    </xsl:for-each> 
    <!-- custom fields -->
    <xsl:for-each select="$custom-fields">
        <xsl:value-of select="name"/>          
        <xsl:if test="position() != last()">
            <xsl:text>,</xsl:text>
        </xsl:if>
    </xsl:for-each>
    <xsl:text>&#10;</xsl:text>
    <!-- data -->
    <xsl:for-each select="issues/issue">
        <xsl:variable name="issue-id" select="id" />
        <!-- standard fields -->
        <xsl:for-each select="*[not(self::custom-values)]">
            <xsl:value-of select="."/>          
            <xsl:text>,</xsl:text>
        </xsl:for-each>
        <!-- custom fields -->
        <xsl:for-each select="$custom-fields">
            <xsl:value-of select="key('custom-value', concat(id, '|', $issue-id))/value"/>          
            <xsl:if test="position() != last()">
                <xsl:text>,</xsl:text>
            </xsl:if>
        </xsl:for-each> 
        <xsl:text>&#10;</xsl:text>
    </xsl:for-each> 
</xsl:template>

</xsl:stylesheet>

应用于您的输入示例,结果将是:

id,project-id,subject,description,Delay,Means of Delivery,Shipping Date
100,10,first helpdesk issue,a small problem,15,,2016-08-01
101,10,second helpdesk issue,a medium problem,10,FTP,
102,10,third helpdesk issue,a huge security problem,,SSH,
103,20,first "development" issue,just some "strange" software,,,

【讨论】:

  • 非常感谢。使用 concat 和祖先创建密钥的想法很棒。
  • 一个小调整:通过在 concat 语句中添加破折号(“-”),您可以防止这两种情况的混淆:custom-field-id=101 和 issue/id=10 vs. custom-field-id=10 和 issue/id=110: concat(custom-field-id, '-', original::issue/id)
  • @divingTobi 你说得对。我总是在连接的值之间放置一个|。我不知道为什么我在这种情况下忽略了这样做。
猜你喜欢
  • 2019-05-20
  • 2013-01-23
  • 2011-09-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-29
  • 2018-09-19
相关资源
最近更新 更多