xml获取参数值childs并输出到csv

发布于 2024-10-23 12:23:02 字数 1531 浏览 1 评论 0原文

我有以下 xml 结构,

<transport titel="vervoer">
  <type titel="car">
    <brand titel="volvo">
      <color titel="kleur">red</color>
    </brand>
  </type>
  <type titel="car">
    <brand titel="volvo">
      <color titel="kleur">green</color>
    </brand>
  </type>
  <type titel="car">
    <brand titel="ford">
      <color titel="kleur">red</color>
    </brand>
  </type>
  <type titel="bike">
    <brand titel="trek">
      <color titel="kleur">blue</color>
    </brand>
  </type>
</transport>

我可以使用以下 xsl 创建一个 csv:

<xsl:template match="/">
  <xsl:for-each select="/transport/type/brand/color">
    <xsl:variable name="color" select="@titel" />
    <xsl:variable name="brand" select="../@titel" />
    <xsl:variable name="type" select="../../@titel"/>
    <xsl:value-of select="concat($type,$brand,$color)" />
  </xsl:for-each>
</xsl:template>

这给出了单行上每个节点的输出:

car,volvo,red  
car,volo.green  
car,ford,red  
bike,trek,blue  

但是这种方法有两个问题
1.有没有办法从顶部遍历树并在可用时显示所有标题?如果存在没有颜色子节点的节点,则不会显示该节点。

<type titel="bike">
  <brand titel="trek">
  </brand>
</type>

2.我想要我的csv的输出如下:

car,volvo,red  
   ,     ,green  
   ,ford,red  
bike,trek,blue  

i have the following xml structure

<transport titel="vervoer">
  <type titel="car">
    <brand titel="volvo">
      <color titel="kleur">red</color>
    </brand>
  </type>
  <type titel="car">
    <brand titel="volvo">
      <color titel="kleur">green</color>
    </brand>
  </type>
  <type titel="car">
    <brand titel="ford">
      <color titel="kleur">red</color>
    </brand>
  </type>
  <type titel="bike">
    <brand titel="trek">
      <color titel="kleur">blue</color>
    </brand>
  </type>
</transport>

i can create a csv with the following xsl:

<xsl:template match="/">
  <xsl:for-each select="/transport/type/brand/color">
    <xsl:variable name="color" select="@titel" />
    <xsl:variable name="brand" select="../@titel" />
    <xsl:variable name="type" select="../../@titel"/>
    <xsl:value-of select="concat($type,$brand,$color)" />
  </xsl:for-each>
</xsl:template>

this gives output with every node on a single row:

car,volvo,red  
car,volo.green  
car,ford,red  
bike,trek,blue  

BUT there are two issues with this approach
1. is there a way to walk the tree from the top and show all titels when available? if there is a node without the color child it will not be displayed.

<type titel="bike">
  <brand titel="trek">
  </brand>
</type>

2.i want the output of my csv like this:

car,volvo,red  
   ,     ,green  
   ,ford,red  
bike,trek,blue  

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

闻呓 2024-10-30 12:23:02

此样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>
    <xsl:key name="kElementByName" match="*/*" use="name()"/>
    <xsl:variable name="vFields"
         select="//*/*[count(.|key('kElementByName',name())[1])=1]"/>
    <xsl:template match="/*/*">
        <xsl:variable name="vCurrent" select="."/>
        <xsl:for-each select="$vFields">
            <xsl:variable name="vField"
                 select="$vCurrent/descendant-or-self::*[
                             name() = name(current())
                         ]"/>
            <xsl:variable name="vValue"
                 select="($vField/@titel|$vField/text())[last()]"/>
            <xsl:if test="position()!=1">,</xsl:if>
            <xsl:value-of
              select="concat(substring('	',1 div not($vValue)),$vValue)"/>
        </xsl:for-each>
        <xsl:text>
</xsl:text>
    </xsl:template>
</xsl:stylesheet>

输出:

car,volvo,red
car,volvo,green
car,ford,red
bike,trek,blue

编辑:按注释的请求进行分组,此样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kTypeByTitel" match="type" use="@titel"/>
    <xsl:key name="kBrandByType-Titel" match="brand"
             use="concat(../@titel,'++',@titel)"/>
    <xsl:template match="/*">
        <xsl:apply-templates
             select="type[count(.|key('kTypeByTitel',@titel)[1])=1]"/>
    </xsl:template>
    <xsl:template match="type">
        <xsl:value-of select="@titel"/>
        <xsl:apply-templates
             select="key('kTypeByTitel',@titel)/brand[
                        count(.|key('kBrandByType-Titel',
                                    concat(../@titel,'++',@titel)
                                )[1]
                        ) = 1
                     ]"/>
    </xsl:template>
    <xsl:template match="brand">
        <xsl:if test="position()!=1">
            <xsl:text>	</xsl:text>
        </xsl:if>
        <xsl:value-of select="concat(',',@titel)"/>
        <xsl:apply-templates select="key('kBrandByType-Titel',
                                         concat(../@titel,'++',@titel)
                                     )"
                             mode="color"/>
    </xsl:template>
    <xsl:template match="brand" mode="color">
        <xsl:if test="position()!=1">
            <xsl:text>	,	</xsl:text>
        </xsl:if>
        <xsl:value-of select="concat(
                                 ',',
                                 (color/@titel|color/text())[last()],
                                 '
'
                              )"/>
    </xsl:template>
</xsl:stylesheet>

输出:

car,volvo,red
    ,   ,green
    ,ford,red
bike,trek,blue

注意:不需要有序的输入源。固定字段,因为通用解决方案(按动态键嵌套分组)将是 XSLT 1.0 中最复杂的任务

This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>
    <xsl:key name="kElementByName" match="*/*" use="name()"/>
    <xsl:variable name="vFields"
         select="//*/*[count(.|key('kElementByName',name())[1])=1]"/>
    <xsl:template match="/*/*">
        <xsl:variable name="vCurrent" select="."/>
        <xsl:for-each select="$vFields">
            <xsl:variable name="vField"
                 select="$vCurrent/descendant-or-self::*[
                             name() = name(current())
                         ]"/>
            <xsl:variable name="vValue"
                 select="($vField/@titel|$vField/text())[last()]"/>
            <xsl:if test="position()!=1">,</xsl:if>
            <xsl:value-of
              select="concat(substring('	',1 div not($vValue)),$vValue)"/>
        </xsl:for-each>
        <xsl:text>
</xsl:text>
    </xsl:template>
</xsl:stylesheet>

Output:

car,volvo,red
car,volvo,green
car,ford,red
bike,trek,blue

EDIT: Grouping as request by comments, this stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kTypeByTitel" match="type" use="@titel"/>
    <xsl:key name="kBrandByType-Titel" match="brand"
             use="concat(../@titel,'++',@titel)"/>
    <xsl:template match="/*">
        <xsl:apply-templates
             select="type[count(.|key('kTypeByTitel',@titel)[1])=1]"/>
    </xsl:template>
    <xsl:template match="type">
        <xsl:value-of select="@titel"/>
        <xsl:apply-templates
             select="key('kTypeByTitel',@titel)/brand[
                        count(.|key('kBrandByType-Titel',
                                    concat(../@titel,'++',@titel)
                                )[1]
                        ) = 1
                     ]"/>
    </xsl:template>
    <xsl:template match="brand">
        <xsl:if test="position()!=1">
            <xsl:text>	</xsl:text>
        </xsl:if>
        <xsl:value-of select="concat(',',@titel)"/>
        <xsl:apply-templates select="key('kBrandByType-Titel',
                                         concat(../@titel,'++',@titel)
                                     )"
                             mode="color"/>
    </xsl:template>
    <xsl:template match="brand" mode="color">
        <xsl:if test="position()!=1">
            <xsl:text>	,	</xsl:text>
        </xsl:if>
        <xsl:value-of select="concat(
                                 ',',
                                 (color/@titel|color/text())[last()],
                                 '
'
                              )"/>
    </xsl:template>
</xsl:stylesheet>

Output:

car,volvo,red
    ,   ,green
    ,ford,red
bike,trek,blue

Note: There is no need for an ordered input source. Fixed fields because a general solution (nested grouping by dynamics keys) would be the most complex task in XSLT 1.0

血之狂魔 2024-10-30 12:23:02

您的问题是您在 for-each 中选择了 ,因此您将错过每个没有的 后代。

使用 for-each 进行处理的替代方法可能是这样的:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" indent="no" />
    <xsl:strip-space elements="transport" />

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

    <xsl:template match="transport">
        <xsl:apply-templates />
    </xsl:template>

    <xsl:template match="type">
        <xsl:choose>
            <xsl:when test="@titel">
                <xsl:value-of select="@titel" />
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="' '" />
            </xsl:otherwise>
        </xsl:choose>

        <xsl:text>,</xsl:text>

        <xsl:choose>
            <xsl:when test="brand[@titel]">
                <xsl:apply-templates select="brand" />
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="' '" />
            </xsl:otherwise>
        </xsl:choose>

        <xsl:text>,</xsl:text>

        <xsl:choose>
            <xsl:when test="brand/color">
                <xsl:apply-templates select="brand/color" />
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="' '" />
            </xsl:otherwise>
        </xsl:choose>
        <xsl:text>
</xsl:text>
    </xsl:template>

    <xsl:template match="brand">
        <xsl:value-of select="@titel"/>
    </xsl:template>

    <xsl:template match="brand/color">
        <xsl:value-of select="."/>
    </xsl:template>
</xsl:stylesheet>

示例输入

<?xml version="1.0" encoding="utf-8" ?>
<transport titel="vervoer">
    <type titel="car">
        <brand titel="volvo">
            <color titel="kleur">red</color>
        </brand>
    </type>
    <type titel="car">
        <brand titel="volvo">
            <color titel="kleur">green</color>
        </brand>
    </type>
    <type titel="car">
        <brand titel="ford">
            <color titel="kleur">red</color>
        </brand>
    </type>
    <type titel="bike">
        <brand titel="trek">
            <color titel="kleur">blue</color>
        </brand>
    </type>
    <type titel="trike">
        <brand titel="foo" />
    </type>
    <type>
        <brand titel="porsche">
            <color titel="kleur">black</color>
        </brand>
    </type>
    <type>
        <brand>
            <color titel="kleur">black</color>
        </brand>
    </type>

示例输出

car,volvo,red
car,volvo,green
car,ford,red
bike,trek,blue
trike,trek, 
 ,porsche,black
 , ,black

要从输出中省略不需要的元素,只需添加一个空模板:

    ...
    <xsl:template match="sometext" />
</xsl:stylesheet>

Your problem is that you select <color> in your for-each so you will miss every <type> that doesn't have a <color> descendant.

An alternative to processing with for-each could be this:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" indent="no" />
    <xsl:strip-space elements="transport" />

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

    <xsl:template match="transport">
        <xsl:apply-templates />
    </xsl:template>

    <xsl:template match="type">
        <xsl:choose>
            <xsl:when test="@titel">
                <xsl:value-of select="@titel" />
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="' '" />
            </xsl:otherwise>
        </xsl:choose>

        <xsl:text>,</xsl:text>

        <xsl:choose>
            <xsl:when test="brand[@titel]">
                <xsl:apply-templates select="brand" />
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="' '" />
            </xsl:otherwise>
        </xsl:choose>

        <xsl:text>,</xsl:text>

        <xsl:choose>
            <xsl:when test="brand/color">
                <xsl:apply-templates select="brand/color" />
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="' '" />
            </xsl:otherwise>
        </xsl:choose>
        <xsl:text>
</xsl:text>
    </xsl:template>

    <xsl:template match="brand">
        <xsl:value-of select="@titel"/>
    </xsl:template>

    <xsl:template match="brand/color">
        <xsl:value-of select="."/>
    </xsl:template>
</xsl:stylesheet>

sample input

<?xml version="1.0" encoding="utf-8" ?>
<transport titel="vervoer">
    <type titel="car">
        <brand titel="volvo">
            <color titel="kleur">red</color>
        </brand>
    </type>
    <type titel="car">
        <brand titel="volvo">
            <color titel="kleur">green</color>
        </brand>
    </type>
    <type titel="car">
        <brand titel="ford">
            <color titel="kleur">red</color>
        </brand>
    </type>
    <type titel="bike">
        <brand titel="trek">
            <color titel="kleur">blue</color>
        </brand>
    </type>
    <type titel="trike">
        <brand titel="foo" />
    </type>
    <type>
        <brand titel="porsche">
            <color titel="kleur">black</color>
        </brand>
    </type>
    <type>
        <brand>
            <color titel="kleur">black</color>
        </brand>
    </type>

sample output

car,volvo,red
car,volvo,green
car,ford,red
bike,trek,blue
trike,trek, 
 ,porsche,black
 , ,black

To omit unwanted elements from your output just add an empty template:

    ...
    <xsl:template match="sometext" />
</xsl:stylesheet>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文