XML到CSV:每个子节点打印行,有时缺少子节点

时间:2016-01-12 23:06:14

标签: xml csv xslt

我需要将以下XML转换为csv。这很棘手有两个原因:1)有多个Support_Order_Detail子元素,每个子元素需要一个单独的行2)第二个记录中没有Support_Order_Detail子元素。我在Support_Order_Detail上使用了previous-sibling匹配,并使用not []函数来处理没有Support_Order_Detail节点的记录。我已经包含了我一直在努力的XSLT,它确实有效。我得到了正确的输出。但是,我知道有更好的方法,我的调试器出错了:

/ Report_Data / Report_Entry [2]的模糊规则匹配 匹配“Report_Data / Report_Entry [not(Support_Order_Detail)]” 和“Report_Data / Report_Entry”

我希望了解是否有人可以建议我不会有重复代码的位置,即两个模板。我想摆脱使用not []函数的那个​​。

Doe,Jane,Child Support,Mandatory,12345
Doe,Jane,Child Support,Mandatory,12345
Dole,Bob,Student Loan,Federal,56789

    <Report_Data>
      <Report_Entry>
          <Worker>
              <Last_Name>Doe</Last_Name>
              <First_Name>Jane</First_Name>
          </Worker>
          <Lien_Type>Support Order</Lien_Type>
          <Lien_Sub_Type>Mandatory</Lien_Sub_Type>
          <Support_Order_Detail>
              <Support_Type Descriptor="Current Child Support">
                  <ID type="Support_Type">CS</ID>
              </Support_Type>
          </Support_Order_Detail>
          <Support_Order_Detail>
              <Support_Type Descriptor="Past Due Child Support">
                  <ID type="Support_Type">PDCS</ID>
              </Support_Type>
          </Support_Order_Detail>
          <Case_ID>12345</Case_ID>
      </Report_Entry>
      <Report_Entry>
          <Worker>
              <Last_Name>Dole</Last_Name>
              <First_Name>Bob</First_Name>
          </Worker>
          <Lien_Type>Student Loan</Lien_Type>
          <Lien_Sub_Type>Federal</Lien_Sub_Type>
          <Case_ID>56789</wd:Case_ID>
      </Report_Entry>
    </Report_Data>

XSLT:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:xs="http://www.w3.org/2001/XMLSchema"
     exclude-result-prefixes="xs"
     xmlns:xtt="urn:com.workday/xtt"
     version="2.0">


    <xsl:template match="/">
        <File xtt:separator="&#xd;&#xa;">
            <xtt:class xtt:name="dateformat" xtt:dateFormat="dd/MM/yyyy"/>
            <xsl:apply-templates/>
        </File>
    </xsl:template>

    <xsl:template match="Report_Data/Report_Entry"> 
        <xsl:apply-templates select="Support_Order_Detail"/>
    </xsl:template>


    <xsl:template match="Support_Order_Detail" >
        <Record xtt:separator=",">
            <LastName xtt:maxLength="14"><xsl:value-of select="preceding-sibling::Worker/Last_Name[1]"/></LastName>
            <FirstName xtt:maxLength="17"><xsl:value-of select="preceding-sibling::Worker/First_Name[1]"/></FirstName>
            <LienType>
            <xsl:choose>
                <xsl:when test="preceding-sibling::Lien_Type[1] = 'Support Order' and Support_Type/@Descriptor = 'Current Child Support'">
                    <xsl:text>Child Support</xsl:text>
                </xsl:when>
                <xsl:when test="preceding-sibling::Lien_Type[1] = 'Support Order' and Support_Type/@Descriptor = 'Past Due Child Support'">
                    <xsl:text>Child Support</xsl:text>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="Support_Type/@Descriptor"/>
                </xsl:otherwise>
            </xsl:choose>
            </LienType>
            <LienSubType><xsl:value-of select="preceding-sibling::Lien_Sub_Type[1]"/></LienSubType>
            <CaseID xtt:maxLength="20"><xsl:value-of select="following-sibling::Case_ID"/></CaseID> 
        </Record>
    </xsl:template>

    <xsl:template match="Report_Data/Report_Entry[not(Support_Order_Detail)]" >
        <Record xtt:separator=",">
            <LastName xtt:maxLength="14"><xsl:value-of select="Worker/Last_Name"/></LastName>
            <FirstName xtt:maxLength="17"><xsl:value-of select="Worker/First_Name"/></FirstName>
            <LienType><xsl:value-of select="Lien_Type"/></LienType>
            <LienSubType><xsl:value-of select="Lien_Sub_Type"/></LienSubType>
            <CaseID xtt:maxLength="20"><xsl:value-of select="Case_ID"/></CaseID> 
        </Record>
    </xsl:template>

</xsl:stylesheet> 

预期的XML结果:

    <Record xtt:separator=",">
        <LastName xtt:maxLength="14">Doe</LastName>
        <FirstName xtt:maxLength="17">Jane</FirstName>
        <LienType>Child Support</LienType>
        <LienSubType>Mandatory</LienSubType>
        <CaseID xtt:maxLength="20">12345</CaseID>
    </Record>
    <Record xtt:separator=",">
        <LastName xtt:maxLength="14">Doe</LastName>
        <FirstName xtt:maxLength="17">Jane</FirstName>
        <LienType>Child Support</LienType>
        <LienSubType>Mandatory</LienSubType>
        <CaseID xtt:maxLength="20">12345</CaseID>
    </Record>
    <Record xtt:separator=",">
        <LastName xtt:maxLength="14">Dole</LastName>
        <FirstName xtt:maxLength="17">Bob</FirstName>
        <LienType>Student Loan</LienType>
        <LienSubType>Federal</LienSubType>
        <CaseID xtt:maxLength="20">56789</CaseID>
    </Record>

2 个答案:

答案 0 :(得分:0)

所以我不知道您使用的任何扩展或工具,但在纯XSLT中执行此操作非常简单;匹配所有Report_Entry个元素,如果他们有Support_Order_Detail个元素循环遍历除last()之外的所有元素(因为我们已经为此生成了一行):< / p>

(我稍微修改了这个以使用变量而不是重复选择)

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="text" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />

    <xsl:template match="//Report_Entry">
        <xsl:variable name="row">
            <xsl:value-of select="Worker/Last_Name" />,<xsl:value-of select="Worker/First_Name" />,<xsl:value-of select="Lien_Type"/><xsl:value-of select="Lien_Sub_Type"/>,<xsl:value-of select="Case_ID"/>
            <xsl:text>&#13;</xsl:text>
        </xsl:variable>

        <xsl:value-of select="$row" />

        <xsl:for-each select="Support_Order_Detail[position() != last()]">            
            <xsl:value-of select="$row" />
        </xsl:for-each>
    </xsl:template>

    <xsl:template match="text()"/>


</xsl:transform> 

http://xsltransform.net/bFN1y9B/1

答案 1 :(得分:0)

  

我在调试器中遇到错误:

     

/ Report_Data / Report_Entry的不明确规则匹配[2]匹配两者   &#34; Report_Data / Report_Entry [否(Support_Order_Detail)]&#34;和   &#34; Report_Data / Report_Entry&#34;

如果更改以下内容,则可以消除错误:

<xsl:template match="Report_Data/Report_Entry">

为:

<xsl:template match="Report_Entry">

同样,您可以替换:

<xsl:template match="Report_Data/Report_Entry[not(Support_Order_Detail)]" >

使用:

<xsl:template match="Report_Entry[not(Support_Order_Detail)]" >

匹配模式不是选择表达式:它不需要包含路径,除非模式没有它(例如,如果你在不同的地方或级别有Report_Entry并且需要区别对待它们。

至于&#34;更好&#34;代码实现相同的结果,这在很大程度上取决于个人喜好。恕我直言,如果你有两种类型的Report_Entry并且每一种都需要以不同的方式处理,那么使用单独的模板来处理它们是最好的方法,除非差异很小(不是你的情况)。

我会考虑简化xsl:choose块。