1

我在上一个问题中尝试了解决方案(将 XML 展平以通过 SSIS 包加载),但这不起作用。我现在知道我需要做什么,但是我需要一些关于如何做的指导。

假设我有以下 XML 结构:

<person id="1">
   <name>John</name>
   <surname>Smith</surname>
   <age>25</age>
   <comment>
      <comment_id>1</comment_id>
      <comment_text>Hello</comment_text>
   </comment>
   <comment>
      <comment_id>2</comment_id>
      <comment_text>Hello again!</comment_text>
   </comment>
   <somethingelse>
       <id>1</id>
   </somethingelse>
   <comment>
      <comment_id>3</comment_id>
      <comment_text>Third Item</comment_text>
   </comment>
</person>
<person id="2">
   <name>John</name>
   <surname>Smith</surname>
   <age>25</age>
   <somethingelse>
       <id>1</id>
   </somethingelse>
</person>
...
...

如果我要将它加载到 SSIS 包中,作为 XML 源,我将得到的是为每个元素创建的表,而不是获得结构化的表输出,例如

  • 人员表(姓名、姓氏、年龄)
  • 其他表(id)
  • 评论表(comment_id,comment_text)

我最终得到的是:

  • 人员表(person_Id <-- 内部 SSIS id)
  • 名称表
  • 姓氏表
  • 年龄表
  • 人名表
  • person_surname 表
  • person_comment_comment_id 表

ETC...

我发现如果每个元素和所有内部元素的格式和一致性不同,我会得到上述异常,这使得它相当复杂,特别是如果我处理 80 - 100+ 列。

不幸的是,我无法修改生成这些报告的系统(Lotus Notes),所以我想知道我是否能够明确地拥有一个 XSLT 模板,该模板能够对齐每个的子元素(以及子集合元素,例如作为评论?除非有更快的方法来重新排列所有内部元素。

似乎 SSIS XML 源在以下意义上需要一个非常一致的 XML 文件:如果名称元素位于位置 1,则人员父级中的所有后续名称元素都必须位于位置 1。

如果从一个父级到另一个父级缺少某些元素,SSIS 似乎会发现不一致,但是,如果它们的顺序不正确 (A, B, C)(A, B, C)(A,C,B),它将大惊小怪!

感谢所有帮助!先感谢您。

4

2 回答 2

2

If you don't want to include a manual definition of how to order things, you could simply order them alphabetically.

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

  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="person">
    <xsl:copy>
      <xsl:apply-templates select="@*" />
      <xsl:apply-templates select="*">
        <xsl:sort data-type="text" select="name()" />
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

This way output order would be predictable and stable, but <name> for example would end up somewhere in the middle, after <comment>. I don't know if that's all-right with SSIS, but I guess it should be.


EDIT: If you want to sort dependent tables (i.e. elements that contain children instead of just text) to the bottom... Well, <xsl:sort> can be applied more than once.

  <xsl:template match="person">
    <xsl:copy>
      <xsl:apply-templates select="@*" />
      <xsl:apply-templates select="*">
        <xsl:sort data-type="number" select="boolean(*)" />
        <xsl:sort data-type="text" select="name()" />
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

Where boolean(*) effectively converts the fact "children" / "no children" to true / false, which in turn (in numerical context, due to data-type="number") is represented as 0 / 1. This way the text-only elements end up before everything else.

于 2013-10-24T15:34:51.533 回答
2

据我了解,您希望为<person>. 查看以下 XSLT 是否接近您所追求的:

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

    <!-- XSLT identity transformation -->
    <xsl:template match="@*|node()" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="person">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="name"/>
            <xsl:apply-templates select="surname"/>
            <xsl:apply-templates select="age"/>
            <xsl:apply-templates select="somethingelse"/>
            <xsl:apply-templates select="comment"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

输出 XML

<?xml version="1.0" encoding="UTF-8"?>
<project>
  <person id="1">
    <name>John</name>
    <surname>Smith</surname>
    <age>25</age>
    <somethingelse>
      <id>1</id>
    </somethingelse>
    <comment>
      <comment_id>1</comment_id>
      <comment_text>Hello</comment_text>
    </comment>
    <comment>
      <comment_id>2</comment_id>
      <comment_text>Hello again!</comment_text>
    </comment>
    <comment>
      <comment_id>3</comment_id>
      <comment_text>Third Item</comment_text>
    </comment>
  </person>
  <person id="2">
    <name>John</name>
    <surname>Smith</surname>
    <age>25</age>
    <somethingelse>
      <id>1</id>
    </somethingelse>
  </person>
</project>
于 2013-10-24T14:13:03.937 回答