导入多个xml文件,过滤,然后在SSIS中输出到不同的xml格式

时间:2012-09-24 08:10:48

标签: sql xml ssis

我有一项任务要求我提取一组xml文件,这些文件都是相关的,然后从这些文件中挑出一部分记录,转换一些列,然后使用不同的格式导出到单个xml文件

我是SSIS的新手,到目前为止,我已经成功地导入了两个xml文件(为简单起见,仅从两个文件开始)。

第一个文件我们称之为“项目”,包含一些基本元数据,其中包括ID,用于识别第二个文件“里程碑”中的相关记录。我在数据流中使用查找转换过滤我的“有效记录” - 现在我有了有效的项ID来获取我需要的记录。我将这些有效的ID(以及Item.xml中的其余列通过Sort,然后进入合并连接)汇总。

第二个文件由2个输出构成,一个包含两列(ItemID和RowID)。第二个包含所有里程碑相关数据和一个RowID。我把这些通过内部合并连接,基于RowID,所以我将ItemID与里程碑数据一起使用。然后我使用ItemID在两个文件上进行完全外连接合并连接。

这给了我这样的数据:

  • ItemID [1] - MilestoneData [2]
  • ItemID [1] - MilestoneData [3]
  • ItemID [1] - MilestoneData [4]
  • ItemID [1] - MilestoneData [5]
  • ItemID [2] - MilestoneData [6]
  • ItemID [2] - MilestoneData [7]
  • ItemID [2] - MilestoneData [8]

我可以通过派生列转换来放置这些数据来创建我实际需要的数据列,但是我无法看到如何以关系方式构造它/将其规范化为不同的xml格式。

想法是输出类似的东西:

<item id="1">
      <Milestone id="2">
      <Milestone />
      <Milestone id="3">
      <Milestone />
</item>

有人能指出我正确的方向吗?

更新 更详细的描述我所拥有的,以及我想要实现的目标:

Item.xml:

 <Items>
     <Item ItemID="1">
         <Title>
         Data
         </Title>
     </Item>
     <Item ItemID="2">
          ...
     </Item>
     ...
 </Items>

Milestone.xml:

  <Milestones>
  <Item ItemID="2">
       <MS id="3">
            <MS_DATA>
             Data
            </MS_DATA>
       </MS>
       <MS id="4">
            <MS_DATA>
             Data
            </MS_DATA>
       </MS>
   </Item>
   <Item ItemID="3">
       <MS id="5">
            <MS_DATA>
             Data
            </MS_DATA>
       </MS>
   </item>
 </Milestones>

当我使用XML源时,它在SSIS中呈现的方式并不完全直观,这意味着Item行和MS行是两个单独的输出。我必须通过连接运行它们才能获得与特定项目对应的里程碑。这里没问题,然后通过与项目的完全外连接运行它,所以我得到一个包含多行的扁平表,其中包含明显相同的项目数据和MS的不同数据。基本上我得到了我试图在我的表中显示的内容,每个独特的MilestoneData都有大量冗余的Item数据。

最后它必须看起来类似于:

 <NewItems>
 <myNewItem ItemID="2">
       <SomeDataDirectlyFromItem>
            e.g. Title
       </SomeDataDirectlyFromItem>
       <DataConstructedFromMultipleColumnsInItem>
            <MyMilestones>
                  <MS_DATA_TRANSFORMED MSID="3">
                       data
                  </MS_DATA_TRANSFORMED>
                  <MS_DATA_TRANSFORMED MSID="4">
                       data
                  </MS_DATA_TRANSFORMED>
            </MyMilestones>
       </DataConstructedFromMultipleColumnsInItem>
  <myNewItem ItemID="3">
       <SomeDataDirectlyFromItem>
            e.g. Title
       </SomeDataDirectlyFromItem>
       <DataConstructedFromMultipleColumnsInItem>
            <MyMilestones>
                  <MS_DATA_TRANSFORMED MSID="5">
                       data
                  </MS_DATA_TRANSFORMED>
            </MyMilestones>
       </DataConstructedFromMultipleColumnsInItem>
 </myNewItem>
 <myNewItem ItemID="4">
       <SomeDataDirectlyFromItem>
            e.g. Title
       </SomeDataDirectlyFromItem>
       <DataConstructedFromMultipleColumnsInItem>
            <MyMilestones></MyMilestones>
       </DataConstructedFromMultipleColumnsInItem>
 </myNewItem>
 </NewItems>

2 个答案:

答案 0 :(得分:0)

我会尝试使用组件类型为script component的{​​{1}}来处理此问题。因为你是ssis的新手,我假设你之前没有使用过它。所以基本上你

  • 定义输入列,您的组件将会期望(即包含transformation
  • 的列input_xml
  • 使用c#创建一个切割和粘在一起的逻辑
  • 定义组件将用于传递转换行的输出列

您将面临最后可能会使用两行的问题,例如

ItemID[1] - MilestoneData[2];...

将导致

ItemID[1] - MilestoneData[2]

我使用Pentaho kettle做了类似的事情,即使没有使用<item id="1"> <Milestone id="2"> 之类的东西来定义自己的逻辑。但我想ssis在这里缺乏任务。

答案 1 :(得分:0)

如何将XML导入关系表(例如在tempdb中),然后使用FOR XML PATH重构XML? FOR XML PATH可以高度控制XML的外观。下面是一个非常简单的例子:

CREATE TABLE #items ( itemId INT PRIMARY KEY, title VARCHAR(50) NULL )
CREATE TABLE #milestones ( itemId INT, msId INT, msData VARCHAR(50) NOT NULL, PRIMARY KEY ( itemId, msId ) )
GO

DECLARE @itemsXML XML

SELECT @itemsXML = x.y
FROM OPENROWSET( BULK 'c:\temp\items.xml', SINGLE_CLOB ) x(y)

INSERT INTO #items ( itemId, title )
SELECT 
    i.c.value('@ItemID', 'INT' ),
    i.c.value('(Title/text())[1]', 'VARCHAR(50)' )
FROM @itemsXML.nodes('Items/Item') i(c)
GO


DECLARE @milestoneXML XML

SELECT @milestoneXML = x.y
FROM OPENROWSET( BULK 'c:\temp\milestone.xml', SINGLE_CLOB ) x(y)

INSERT INTO #milestones ( itemId, msId, msData )
SELECT 
    i.c.value('@ItemID', 'INT' ),
    i.c.value('(MS/@id)[1]', 'VARCHAR(50)' ) msId,
    i.c.value('(MS/MS_DATA/text())[1]', 'VARCHAR(50)' ) msData
FROM @milestoneXML.nodes('Milestones/Item') i(c)
GO

SELECT 
    i.itemId AS "@ItemID"
FROM #items i
    INNER JOIN #milestones ms ON i.itemId = ms.itemId
FOR XML PATH('myNewItem'), ROOT('NewItems'), TYPE


DROP TABLE #items 
DROP TABLE #milestones