2014-01-09 51 views
0

更新,包括一些额外的细微差别复杂的场景为XSLT

我有一个XML的情况,这将需要一些复杂的XSLT。我一直试图自己弄清楚,但迄今为止还没有失败。

首先,这里是一个模拟XML结构。

<Author id="1234"> 
    <reviews>poor</reviews> 
    <Media>  
    <MediaSet> 
     <MediaCode type="CD">474747</MediaCode> 
    </MediaSet> 
    <MediaSet> 
     <MediaCode type="CD">535353</MediaCode> 
    </MediaSet> 
    <MediaSet> 
     <MediaCode type="eBook">989898</MediaCode> 
    </MediaSet> 
    <MediaSet> 
     <MediaCode type="download">202020</MediaCode> 
    </MediaSet> 
    <MediaSet> 
     <MediaCode type="book">161616</MediaCode> 
    </MediaSet> 
    <MediaSet> 
     <MediaCode type="DVD">828282</MediaCode> 
    </MediaSet> 
    <MediaSet> 
     <OtherCode type="widget" number="747474"/> <!--note different element name and structure--> 
    </MediaSet> 
    </Media> 
    <name>JimBob</name> 
</Author> 

这个例子是什么我处理的大大简化版本,但我想创建一个输出看起来是这样的一个数据库导入:

<row> 
    <field name="authorID">1234</field> 
    <field name="reviews">poor</field> 
    <field name="CD">474747</field> 
    <field name="name">JimBob</field> 
</row> 
<row> 
    <field name="authorID">1234</field> 
    <field name="reviews">poor</field> 
    <field name="CD">535353</field> 
    <field name="name">JimBob</field> 
</row> 
<row> 
    <field name="authorID">1234</field> 
    <field name="reviews">poor</field> 
    <field name="eBook">989898</field> 
    <field name="name">JimBob</field> 
</row> 
<row> 
    <field name="authorID">1234</field> 
    <field name="reviews">poor</field> 
    <field name="download">989898</field> 
    <field name="name">JimBob</field> 
</row> 
<row> 
    <field name="authorID">1234</field> 
    <field name="reviews">poor</field> 
    <field name="widget">555555</field> 
    <field name="name">JimBob</field> 
</row> 
  • CD,电子书下载可能会发生零次或多次。
  • 我需要为每个实例创建一个单独的行
  • 我想忽略某些元素(例如“book”,“DVD”等等)。
  • 还有的“作者”每个“MediaCodes”自己的独特组合100,000s。
  • 有我需要从

我的代码把它从开始XML结构来排了数据库导入/场XML结构工作正常,我处理这个问题拉数据混合元素在存在多个数据点的情况下迭代XML并创建多行。

这是不是可以用XSLT单独管理或我将不得不使用另一种语言来处理?

值得注意的是,我正在处理的XML文件有更复杂的结构,并且大约是325MB

+1

如果您已经“有从起始XML结构到行/字段XML结构的代码”,请将其发布到此处(如果它的整体时间太长,则为其片段)。 –

+0

我回答了您的问题“原样”。但是,恕我直言,你在将结构导入数据库之前将结构展平,这是一个错误。假设一个关系数据库,将两次数据导入两个单独的表格:作者和媒体,而不是一个冗余重复相同数据的平坦表格。 –

+0

另外,对于媒体类型,您应该有一个单独的字段,其中“CD”,“Ebook”等是*值*,另一个字段用于媒体代码,对于所有类型都是通用的。否则,搜索数据库将变得非常繁琐。 –

回答

2

首先,无论你的例子,输入和输出,是无效的。输入尤其如此,由于开始和结束标记之间的许多不匹配,例如:

<MediaCode type="eBook">989898</Type> 

假设一个校正后的输入,其中还包括一个根元素:

<Authors> 
    <Author id="1234"> 
     <reviews>poor</reviews> 
     <MediaSet> 
      <MediaCode type="CD">101</MediaCode> 
      <MediaCode type="CD">102</MediaCode> 
      <MediaCode type="eBook">111</MediaCode> 
      <MediaCode type="download">121</MediaCode> 
      <MediaCode type="book">131</MediaCode> 
     </MediaSet> 
     <name>Adam</name> 
    </Author> 
    <Author id="5678"> 
     <reviews>good</reviews> 
     <MediaSet> 
      <MediaCode type="CD">201</MediaCode> 
      <MediaCode type="eBook">202</MediaCode> 
      <MediaCode type="download">203</MediaCode> 
      <MediaCode type="book">204</MediaCode> 
     </MediaSet> 
     <name>Betty</name> 
    </Author> 
</Authors> 

可以使用样式表等此:

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

<xsl:template match="/"> 
<rows> 
    <xsl:for-each select="Authors/Author/MediaSet/MediaCode[@type!='book']"> 
     <row> 
      <field name="authorID"><xsl:value-of select="../../@id" /></field> 
      <field name="reviews"><xsl:value-of select="../../reviews" /></field> 
      <field name="{@type}"><xsl:value-of select="." /></field> 
      <field name="name"><xsl:value-of select="../../name" /></field> 
     </row> 
    </xsl:for-each> 
</rows> 
</xsl:template> 
</xsl:stylesheet> 

以产生以下结果(再次,与一个根元素):

<?xml version="1.0" encoding="utf-8"?> 
<rows> 
    <row> 
    <field name="authorID">1234</field> 
    <field name="reviews">poor</field> 
    <field name="CD">101</field> 
    <field name="name">Adam</field> 
    </row> 
    <row> 
    <field name="authorID">1234</field> 
    <field name="reviews">poor</field> 
    <field name="CD">102</field> 
    <field name="name">Adam</field> 
    </row> 
    <row> 
    <field name="authorID">1234</field> 
    <field name="reviews">poor</field> 
    <field name="eBook">111</field> 
    <field name="name">Adam</field> 
    </row> 
    <row> 
    <field name="authorID">1234</field> 
    <field name="reviews">poor</field> 
    <field name="download">121</field> 
    <field name="name">Adam</field> 
    </row> 
    <row> 
    <field name="authorID">5678</field> 
    <field name="reviews">good</field> 
    <field name="CD">201</field> 
    <field name="name">Betty</field> 
    </row> 
    <row> 
    <field name="authorID">5678</field> 
    <field name="reviews">good</field> 
    <field name="eBook">202</field> 
    <field name="name">Betty</field> 
    </row> 
    <row> 
    <field name="authorID">5678</field> 
    <field name="reviews">good</field> 
    <field name="download">203</field> 
    <field name="name">Betty</field> 
    </row> 
</rows> 
+0

感谢您的评论,我修改了该问题以反映我的原始示例中未显示的其他复杂性。 – user859501

+1

@ user859501这是一个相当微不足道的变化:只需在for-each路径中使用*而不是MediaCode。我也重申我的建议,不要这样做。 –

1

AFAIKS,这都不复杂:

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

    <xsl:output indent="yes"/> 

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

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

    <xsl:template match="Author/MediaSet/MediaCode[@type!='book']"> 
    <row> 
     <field name="authorId"><xsl:value-of select="../../@id"/></field> 
     <field name="reviews"><xsl:value-of select="../../reviews"/></field> 
     <field name="{@type}"><xsl:value-of select="."/></field> 
     <field name="name"><xsl:value-of select="../../name"/></field> 
    </row> 
    </xsl:template> 
</xsl:stylesheet> 
+0

感谢您的评论,我修改了这个任务,以反映我的原始示例中未显示的其他复杂性。 – user859501