XSLT从另一个节点选择属性

发布于 2025-01-26 14:55:23 字数 2043 浏览 3 评论 0原文

这是我的XML文件:

<root>
    <headers>
        <header value="type1" />
        <header value="type3" />
        <header value="type2" />
    </headers>
    <data type1="data1_1" type2="data1_2" type3="data1_3" />
    <data type1="data2_1" type2="data2_2" type3="data2_3" />
</root>

我想生成CSV,仅在标题部分中列出标题。这是我的XSLT文件:

<?xml version="1.0" encoding="UTF-16"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" indent="no" encoding="unicode" />
<xsl:template match="root">
     <xsl:apply-templates/>
</xsl:template>


<xsl:template match="headers">
    <xsl:apply-templates/><xsl:text>&#xa;</xsl:text>
</xsl:template>


<xsl:template name="separator">
    <xsl:text>&#x09;</xsl:text>
</xsl:template>

<!-- display first line header work ok -->
<xsl:template match="header">
    <xsl:value-of select="@value" />
    <xsl:if test="position() != last()">
      <xsl:call-template name="separator" />
   </xsl:if>
</xsl:template>


<xsl:key name="mykey" match="header" use="@value" />

<!-- For each data parameters check if exist in header and display with the good order ! NOT WORK -->
<xsl:template match="data">
    <xsl:for-each select="@*">
        <xsl:if test="key('mykey', name())">
            <xsl:value-of select="." />
            <xsl:if test="position() != last()">
                <xsl:call-template name="separator" />
            </xsl:if>
        </xsl:if>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

我想要此输出格式(CSV):

type1 type3 type2
data1_1 data1_3 data1_2
data2_1 data2_3 data2_2

但是我的输出是(数据Type2不在正确的标题下):

type1 type3 type2
data1_1 data1_2 data1_3
data2_1 data2_2 data2_3

This is my XML file :

<root>
    <headers>
        <header value="type1" />
        <header value="type3" />
        <header value="type2" />
    </headers>
    <data type1="data1_1" type2="data1_2" type3="data1_3" />
    <data type1="data2_1" type2="data2_2" type3="data2_3" />
</root>

And I want to generate CSV with only headers listed in headers section. This is my xslt file :

<?xml version="1.0" encoding="UTF-16"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" indent="no" encoding="unicode" />
<xsl:template match="root">
     <xsl:apply-templates/>
</xsl:template>


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


<xsl:template name="separator">
    <xsl:text>	</xsl:text>
</xsl:template>

<!-- display first line header work ok -->
<xsl:template match="header">
    <xsl:value-of select="@value" />
    <xsl:if test="position() != last()">
      <xsl:call-template name="separator" />
   </xsl:if>
</xsl:template>


<xsl:key name="mykey" match="header" use="@value" />

<!-- For each data parameters check if exist in header and display with the good order ! NOT WORK -->
<xsl:template match="data">
    <xsl:for-each select="@*">
        <xsl:if test="key('mykey', name())">
            <xsl:value-of select="." />
            <xsl:if test="position() != last()">
                <xsl:call-template name="separator" />
            </xsl:if>
        </xsl:if>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

I want this output format (CSV):

type1 type3 type2
data1_1 data1_3 data1_2
data2_1 data2_3 data2_2

But my output is ( data type2 is not under correct header ):

type1 type3 type2
data1_1 data1_2 data1_3
data2_1 data2_2 data2_3

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

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

发布评论

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

评论(3

送舟行 2025-02-02 14:55:23

我会简单地做:

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:template match="/root">
    <xsl:variable name="headers" select="headers/header" />
    <!-- header -->
    <xsl:for-each select="$headers">
        <xsl:value-of select="@value"/>
        <xsl:if test="position()!=last()">
            <xsl:text>	</xsl:text>
        </xsl:if>
    </xsl:for-each>
    <xsl:text>
</xsl:text>
    <!-- data -->
    <xsl:for-each select="data">
        <xsl:variable name="data" select="." />
        <xsl:for-each select="$headers">
            <xsl:value-of select="$data/@*[name()=current()/@value]"/>
            <xsl:if test="position()!=last()">
                <xsl:text>	</xsl:text>
            </xsl:if>
        </xsl:for-each> 
        <xsl:text>
</xsl:text>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

替代(也许更有效),您可以做:

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="data-value" match="data/@*" use="concat(name(), '|', generate-id(..))" />

<xsl:template match="/root">
    <xsl:variable name="headers" select="headers/header" />
    <!-- header -->
    <xsl:for-each select="$headers">
        <xsl:value-of select="@value"/>
        <xsl:if test="position()!=last()">
            <xsl:text>	</xsl:text>
        </xsl:if>
    </xsl:for-each>
    <xsl:text>
</xsl:text>
    <!-- data -->
    <xsl:for-each select="data">
        <xsl:variable name="data-id" select="generate-id()" />
        <xsl:for-each select="$headers">
            <xsl:value-of select="key('data-value', concat(@value, '|', $data-id))"/>
            <xsl:if test="position()!=last()">
                <xsl:text>	</xsl:text>
            </xsl:if>
        </xsl:for-each> 
        <xsl:text>
</xsl:text>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

btw,结果是一个选项卡分离的文件,而不是CSV 。

I would do simply:

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:template match="/root">
    <xsl:variable name="headers" select="headers/header" />
    <!-- header -->
    <xsl:for-each select="$headers">
        <xsl:value-of select="@value"/>
        <xsl:if test="position()!=last()">
            <xsl:text>	</xsl:text>
        </xsl:if>
    </xsl:for-each>
    <xsl:text>
</xsl:text>
    <!-- data -->
    <xsl:for-each select="data">
        <xsl:variable name="data" select="." />
        <xsl:for-each select="$headers">
            <xsl:value-of select="$data/@*[name()=current()/@value]"/>
            <xsl:if test="position()!=last()">
                <xsl:text>	</xsl:text>
            </xsl:if>
        </xsl:for-each> 
        <xsl:text>
</xsl:text>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

Alternatively (and perhaps a bit more efficiently), you could do:

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="data-value" match="data/@*" use="concat(name(), '|', generate-id(..))" />

<xsl:template match="/root">
    <xsl:variable name="headers" select="headers/header" />
    <!-- header -->
    <xsl:for-each select="$headers">
        <xsl:value-of select="@value"/>
        <xsl:if test="position()!=last()">
            <xsl:text>	</xsl:text>
        </xsl:if>
    </xsl:for-each>
    <xsl:text>
</xsl:text>
    <!-- data -->
    <xsl:for-each select="data">
        <xsl:variable name="data-id" select="generate-id()" />
        <xsl:for-each select="$headers">
            <xsl:value-of select="key('data-value', concat(@value, '|', $data-id))"/>
            <xsl:if test="position()!=last()">
                <xsl:text>	</xsl:text>
            </xsl:if>
        </xsl:for-each> 
        <xsl:text>
</xsl:text>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

BTW, the result is a tab-separated file, not CSV.

早乙女 2025-02-02 14:55:23

属性没有设置顺序。元素可以。因此,让我们使用这些元素提供您的订购:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" indent="no" encoding="unicode" />
<xsl:template match="Results">
     <xsl:apply-templates/>
</xsl:template>

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

<xsl:template name="separator">
    <xsl:text>	</xsl:text>
</xsl:template>

<!-- display first line header work ok -->
<xsl:template match="header">
    <xsl:value-of select="@value" />
    <xsl:if test="position() != last()">
      <xsl:call-template name="separator" />
   </xsl:if>
</xsl:template>

<!-- Use the order of the headers to choose the order of the attributes. -->
<xsl:template match="data">
    <xsl:variable name="data" select="."/>
    <xsl:for-each select="/root/headers/header">
        <xsl:value-of select="$data/@*[name()=current()/@value]"/>        
            <xsl:if test="position() != last()">
                <xsl:call-template name="separator" />
            </xsl:if>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

输出:

    type1   
    type3   
    type2   


data1_1 data1_3 data1_2
data2_1 data2_3 data2_2

标题在单独的行上,因为我没有更改代码的那一部分。

Attributes have no set order. Elements do. So let's use the elements to provide your ordering:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" indent="no" encoding="unicode" />
<xsl:template match="Results">
     <xsl:apply-templates/>
</xsl:template>

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

<xsl:template name="separator">
    <xsl:text>	</xsl:text>
</xsl:template>

<!-- display first line header work ok -->
<xsl:template match="header">
    <xsl:value-of select="@value" />
    <xsl:if test="position() != last()">
      <xsl:call-template name="separator" />
   </xsl:if>
</xsl:template>

<!-- Use the order of the headers to choose the order of the attributes. -->
<xsl:template match="data">
    <xsl:variable name="data" select="."/>
    <xsl:for-each select="/root/headers/header">
        <xsl:value-of select="$data/@*[name()=current()/@value]"/>        
            <xsl:if test="position() != last()">
                <xsl:call-template name="separator" />
            </xsl:if>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

Output:

    type1   
    type3   
    type2   


data1_1 data1_3 data1_2
data2_1 data2_3 data2_2

The headers are on separate lines because I didn't change that part of your code.

爱的十字路口 2025-02-02 14:55:23
  1. 为文本()节点创建一个模板,以摆脱元素(新行,凹痕)之间的所有文本,
  2. 这是您的XSLT之间的新线,

这是您的XSLT,其中XSLT的次要修复程序可以执行您想要的工作:

<?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" encoding="unicode" />
    
    <xsl:template match="root">
        <xsl:apply-templates/>
    </xsl:template>
            
    <xsl:template match="headers">
        <xsl:apply-templates/><xsl:text>
</xsl:text>
    </xsl:template>
    
    <xsl:template match="text()"></xsl:template>
    
    <xsl:template name="separator">
        <xsl:text> </xsl:text>
    </xsl:template>
    
    <!-- display first line header work ok -->
    <xsl:template match="header">
        <xsl:value-of select="@value" />
        <xsl:if test="position() != last()">
            <xsl:call-template name="separator" />
        </xsl:if>
    </xsl:template>
    
    
    <xsl:key name="mykey" match="header" use="@value" />
    
    <!-- For each data parameters check if exist in header and display with the good order ! NOT WORK -->
    <xsl:template match="data">
        <xsl:for-each select="@*">
            <xsl:if test="key('mykey', name())">
                <xsl:value-of select="." />
                <xsl:choose>
                    <xsl:when test="position() != last()">
                        <xsl:call-template name="separator" />
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:text>
</xsl:text>
                    </xsl:otherwise>
                </xsl:choose>
                
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
    
</xsl:stylesheet>
  1. Create a template for text() nodes to get rid of all the text between elements (new lines, indents)
  2. Put new lines between rows explicitly

Here is your xslt with minor fixes that does what you want:

<?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" encoding="unicode" />
    
    <xsl:template match="root">
        <xsl:apply-templates/>
    </xsl:template>
            
    <xsl:template match="headers">
        <xsl:apply-templates/><xsl:text>
</xsl:text>
    </xsl:template>
    
    <xsl:template match="text()"></xsl:template>
    
    <xsl:template name="separator">
        <xsl:text> </xsl:text>
    </xsl:template>
    
    <!-- display first line header work ok -->
    <xsl:template match="header">
        <xsl:value-of select="@value" />
        <xsl:if test="position() != last()">
            <xsl:call-template name="separator" />
        </xsl:if>
    </xsl:template>
    
    
    <xsl:key name="mykey" match="header" use="@value" />
    
    <!-- For each data parameters check if exist in header and display with the good order ! NOT WORK -->
    <xsl:template match="data">
        <xsl:for-each select="@*">
            <xsl:if test="key('mykey', name())">
                <xsl:value-of select="." />
                <xsl:choose>
                    <xsl:when test="position() != last()">
                        <xsl:call-template name="separator" />
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:text>
</xsl:text>
                    </xsl:otherwise>
                </xsl:choose>
                
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
    
</xsl:stylesheet>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文