使用循环函数使用xsl将复杂xml转换为csv

时间:2011-04-04 03:00:54

标签: xml xslt

我在这里有一个xml文件..

<?xml version="1.0" encoding="utf-8" ?>

<!DOCTYPE dependencies SYSTEM "http://depfind.sourceforge.net/dtd/dependencies.dtd">

<dependencies>
    <package confirmed="yes">
        <name>com.infopro.Dependency</name>
        <class confirmed="yes">
            <name>com.infopro.Dependency.A</name>
            <outbound type="class" confirmed="no">java.lang.Object</outbound>
            <outbound type="class" confirmed="no">javax.ejb.Stateless</outbound>
            <inbound type="feature" confirmed="yes">com.infopro.Dependency.B.B()</inbound>
            <inbound type="feature" confirmed="yes">com.infopro.Dependency.B.a</inbound>
            <feature confirmed="yes">
                <name>com.infopro.Dependency.A.A()</name>
                <outbound type="feature" confirmed="yes">com.infopro.Dependency.A.b</outbound>
                <outbound type="class" confirmed="yes">com.infopro.Dependency.B</outbound>
                <outbound type="feature" confirmed="yes">com.infopro.Dependency.B.B()</outbound>
                <outbound type="feature" confirmed="no">java.lang.Object.Object()</outbound>
                <inbound type="feature" confirmed="yes">com.infopro.Dependency.B.B()</inbound>
            </feature>
            <feature confirmed="yes">
                <name>com.infopro.Dependency.A.b</name>
                <outbound type="class" confirmed="yes">com.infopro.Dependency.B</outbound>
                <inbound type="feature" confirmed="yes">com.infopro.Dependency.A.A()</inbound>
            </feature>
            <feature confirmed="yes">
                <name>com.infopro.Dependency.A.check(java.lang.String, java.lang.String)</name>
                <outbound type="feature" confirmed="yes">com.infopro.Dependency.A.stat</outbound>
                <outbound type="class" confirmed="no">java.lang.String</outbound>
                <inbound type="feature" confirmed="yes">com.infopro.Dependency.A.doStatus()</inbound>
            </feature>
            <feature confirmed="yes">
                <name>com.infopro.Dependency.A.doStatus()</name>
                <outbound type="feature" confirmed="yes">com.infopro.Dependency.A.check(java.lang.String, java.lang.String)</outbound>
                <outbound type="feature" confirmed="yes">com.infopro.Dependency.A.name</outbound>
                <outbound type="feature" confirmed="yes">com.infopro.Dependency.A.user_id</outbound>
                <outbound type="class" confirmed="no">java.lang.String</outbound>
            </feature>
            <feature confirmed="yes">
                <name>com.infopro.Dependency.A.name</name>
                <outbound type="class" confirmed="no">java.lang.String</outbound>
                <inbound type="feature" confirmed="yes">com.infopro.Dependency.A.doStatus()</inbound>
            </feature>
            <feature confirmed="yes">
                <name>com.infopro.Dependency.A.stat</name>
                <outbound type="class" confirmed="no">java.lang.String</outbound>
                <inbound type="feature" confirmed="yes">com.infopro.Dependency.A.check(java.lang.String, java.lang.String)</inbound>
            </feature>
            <feature confirmed="yes">
                <name>com.infopro.Dependency.A.user_id</name>
                <outbound type="class" confirmed="no">java.lang.String</outbound>
                <inbound type="feature" confirmed="yes">com.infopro.Dependency.A.doStatus()</inbound>
            </feature>
        </class>
        <class confirmed="yes">
            <name>com.infopro.Dependency.B</name>
            <outbound type="class" confirmed="yes">com.infopro.Dependency.C</outbound>
            <outbound type="class" confirmed="no">java.lang.Object</outbound>
            <outbound type="class" confirmed="no">javax.ejb.Stateless</outbound>
            <inbound type="feature" confirmed="yes">com.infopro.Dependency.A.A()</inbound>
            <inbound type="feature" confirmed="yes">com.infopro.Dependency.A.b</inbound>
            <feature confirmed="yes">
                <name>com.infopro.Dependency.B.B()</name>
                <outbound type="class" confirmed="yes">com.infopro.Dependency.A</outbound>
                <outbound type="feature" confirmed="yes">com.infopro.Dependency.A.A()</outbound>
                <outbound type="feature" confirmed="yes">com.infopro.Dependency.B.a</outbound>
                <outbound type="feature" confirmed="no">java.lang.Object.Object()</outbound>
                <inbound type="feature" confirmed="yes">com.infopro.Dependency.A.A()</inbound>
            </feature>
            <feature confirmed="yes">
                <name>com.infopro.Dependency.B.a</name>
                <outbound type="class" confirmed="yes">com.infopro.Dependency.A</outbound>
                <inbound type="feature" confirmed="yes">com.infopro.Dependency.B.B()</inbound>
            </feature>
            <feature confirmed="yes">
                <name>com.infopro.Dependency.B.check(java.lang.String, java.lang.String)</name>
                <outbound type="feature" confirmed="yes">com.infopro.Dependency.B.stat</outbound>
                <outbound type="class" confirmed="no">java.lang.String</outbound>
                <inbound type="feature" confirmed="yes">com.infopro.Dependency.B.doStatus()</inbound>
            </feature>
            <feature confirmed="yes">
                <name>com.infopro.Dependency.B.doStatus()</name>
                <outbound type="feature" confirmed="yes">com.infopro.Dependency.B.check(java.lang.String, java.lang.String)</outbound>
                <outbound type="feature" confirmed="yes">com.infopro.Dependency.B.name</outbound>
                <outbound type="feature" confirmed="yes">com.infopro.Dependency.B.user_id</outbound>
                <outbound type="class" confirmed="no">java.lang.String</outbound>
            </feature>
            <feature confirmed="yes">
                <name>com.infopro.Dependency.B.name</name>
                <outbound type="class" confirmed="no">java.lang.String</outbound>
                <inbound type="feature" confirmed="yes">com.infopro.Dependency.B.doStatus()</inbound>
            </feature>
            <feature confirmed="yes">
                <name>com.infopro.Dependency.B.stat</name>
                <outbound type="class" confirmed="no">java.lang.String</outbound>
                <inbound type="feature" confirmed="yes">com.infopro.Dependency.B.check(java.lang.String, java.lang.String)</inbound>
            </feature>
            <feature confirmed="yes">
                <name>com.infopro.Dependency.B.user_id</name>
                <outbound type="class" confirmed="no">java.lang.String</outbound>
                <inbound type="feature" confirmed="yes">com.infopro.Dependency.B.doStatus()</inbound>
            </feature>
        </class>
        <class confirmed="yes">
            <name>com.infopro.Dependency.C</name>
            <outbound type="class" confirmed="no">java.lang.Object</outbound>
            <outbound type="class" confirmed="no">javax.ejb.Remote</outbound>
            <inbound type="class" confirmed="yes">com.infopro.Dependency.B</inbound>
            <feature confirmed="yes">
                <name>com.infopro.Dependency.C.doStatus()</name>
            </feature>
        </class>
    </package>
    <package confirmed="no">
        <name>java.lang</name>
        <class confirmed="no">
            <name>java.lang.Object</name>
            <inbound type="class" confirmed="yes">com.infopro.Dependency.A</inbound>
            <inbound type="class" confirmed="yes">com.infopro.Dependency.B</inbound>
            <inbound type="class" confirmed="yes">com.infopro.Dependency.C</inbound>
            <feature confirmed="no">
                <name>java.lang.Object.Object()</name>
                <inbound type="feature" confirmed="yes">com.infopro.Dependency.A.A()</inbound>
                <inbound type="feature" confirmed="yes">com.infopro.Dependency.B.B()</inbound>
            </feature>
        </class>
        <class confirmed="no">
            <name>java.lang.String</name>
            <inbound type="feature" confirmed="yes">com.infopro.Dependency.A.check(java.lang.String, java.lang.String)</inbound>
            <inbound type="feature" confirmed="yes">com.infopro.Dependency.A.doStatus()</inbound>
            <inbound type="feature" confirmed="yes">com.infopro.Dependency.A.name</inbound>
            <inbound type="feature" confirmed="yes">com.infopro.Dependency.A.stat</inbound>
            <inbound type="feature" confirmed="yes">com.infopro.Dependency.A.user_id</inbound>
            <inbound type="feature" confirmed="yes">com.infopro.Dependency.B.check(java.lang.String, java.lang.String)</inbound>
            <inbound type="feature" confirmed="yes">com.infopro.Dependency.B.doStatus()</inbound>
            <inbound type="feature" confirmed="yes">com.infopro.Dependency.B.name</inbound>
            <inbound type="feature" confirmed="yes">com.infopro.Dependency.B.stat</inbound>
            <inbound type="feature" confirmed="yes">com.infopro.Dependency.B.user_id</inbound>
        </class>
    </package>
    <package confirmed="no">
        <name>javax.ejb</name>
        <class confirmed="no">
            <name>javax.ejb.Remote</name>
            <inbound type="class" confirmed="yes">com.infopro.Dependency.C</inbound>
        </class>
        <class confirmed="no">
            <name>javax.ejb.Stateless</name>
            <inbound type="class" confirmed="yes">com.infopro.Dependency.A</inbound>
            <inbound type="class" confirmed="yes">com.infopro.Dependency.B</inbound>
        </class>
    </package>
</dependencies>

我想以这种格式创建csv文件的输出..

classname1, outbound.

classname1, outbound.

.             .

.             .

classname1, inbound.

.             .

.             .

classname2, outbound.

.             .

classname2, inbound.

依旧......

现在我面临的挑战是每个班级的入站和出站数量是不同的,并且各不相同。所以我必须为此指定循环。而且我只需要类名包含“com”关键字或字符串里面不包括包名,功能名全部。我需要做这个xsl,以便对于我生成的所有类似的xml,我可以将其更改为csv表格,以便我需要进一步处理数据。

我创建的xsl如下所示,但我仍面临一些错误和问题

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

    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/> 


    <xsl:template match="class[contains(.//text(), 'com')]">
        <xsl:text></xsl:text><xsl:value-of select="name"/><xsl:if test="@confirmed='no'"> *</xsl:if><xsl:text> </xsl:text>
        <xsl:for-each select="outbound[contains(.//text(), 'com')]">
            <xsl:text disable-output-escaping="yes">   , </xsl:text><xsl:value-of select="."/><xsl:if test="@confirmed='no'"> *</xsl:if><xsl:text>
</xsl:text>
        </xsl:for-each>
        <xsl:for-each select="inbound[contains(.//text(), 'com')]">
            <xsl:text disable-output-escaping="yes">   , </xsl:text><xsl:value-of select="."/><xsl:if test="@confirmed='no'"> *</xsl:if><xsl:text>
</xsl:text>
        </xsl:for-each>
    </xsl:template>  
</xsl:stylesheet>

输出为

com.infopro.Dependencycom.infopro.Dependency.A                               , com.infopro.Dependency.B.B()
                                                                             , com.infopro.Dependency.B.a
com.infopro.Dependency.B                                                     , com.infopro.Dependency.C
                                                                             , com.infopro.Dependency.A.A()
                                                                             , com.infopro.Dependency.A.b
com.infopro.Dependency.C                                                     , com.infopro.Dependency.B
java.langjava.lang.Objectcom.infopro.Dependency.Acom.infopro.Dependency.Bcom.infopro.Dependency.Cjava.lang.Object.Object()com.infopro.Dependency.A.A()com.infopro.Dependency.B.B()java.lang.Stringcom.infopro.Dependency.A.check(java.lang.String, java.lang.String)com.infopro.Dependency.A.doStatus()com.infopro.Dependency.A.namecom.infopro.Dependency.A.statcom.infopro.Dependency.A.user_idcom.infopro.Dependency.B.check(java.lang.String, java.lang.String)com.infopro.Dependency.B.doStatus()com.infopro.Dependency.B.namecom.infopro.Dependency.B.statcom.infopro.Dependency.B.user_idjavax.ejbjavax.ejb.Remotecom.infopro.Dependency.Cjavax.ejb.Statelesscom.infopro.Dependency.Acom.infopro.Dependency.B

表格排列几乎发生但是包名称仍然存在第一类名称的问题,以及最后一些长链不需要的java字符串。 希望得到指导和帮助。谢谢

1 个答案:

答案 0 :(得分:2)

好吧,你不必做任何明确的循环。你可以做任何你想用模板做的事情。

要有效地编写XSLT,您必须考虑转换。想想,“我想把输入中的一些东西转换成输出中的某些东西。”那些东西是什么?你没有在你的问题中阐明它们,你可能没有在设计中明确表达它们。

看起来你想要的是将每个package元素转换为输出中的一行。所以你需要一个模板。每一行的第一件事是包名称(即name元素的文本内容),最后一件事是换行符。所以从这开始:

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

<xsl:template match="package">
   <xsl:value-of select="name/text()"/>
   <!-- something will go in here -->
   <xsl:text>&#x0a;</xsl:text>
</xsl:template>

如果在输入文档中运行该转换,(假设您已将其放入实际样式表中),则应获得所有包名称的简单列表作为输出。

现在,您要将outboundinbound元素的内容添加为每行上的其他逗号分隔元素。什么是转型?如果confirmed属性等于no,则需要将这些元素中的每一个转换为包含逗号,元素的文本内容和星号的文本。

这很容易实现:只需创建这些元素的模板,然后在package模板中应用它们。由于您只希望显示文本内容以con.开头的元素,因此在应用模板时添加谓词:

<xsl:template match="package">
   <xsl:value-of select="name/text()"/>
   <xsl:apply-templates select="output[contains(text(), '.com')]"/>
   <xsl:apply-templates select="input[contains(text(), '.com')]"/>
   <xsl:text>&#x0a;</xsl:text>
</xsl:template>

<xsl:template match="output|input">
   <xsl:text>, </xsl:text>
   <xsl:value-of select="text()"/>
   <xsl:if test="@confirmed='no'">
      <xsl:text> *</xsl:text>
   </xsl:text>
</xsl:text>

这种设计和实现方法的两个重要因素:首先,您使用模板来转换节点,而不是尝试使用非专门设计的语言进行过程编程。

其次,您只是在转换您明确选择的节点。您现在在输出结束时收到垃圾的原因是您已将模板应用于您认为未应用它们的节点:您没有创建应用于文档根目录的模板,并且所以XSLT处理器正在为它找到的每个元素应用内置模板。