重新排序XML元素或使用XSLT设置显式模板

时间:2013-10-24 13:21:24

标签: xml xslt ssis

我在上一个问题(flattening XML to load via SSIS package)中尝试了解决方案,但这不起作用。我现在知道我需要做什么,但是我需要一些如何做的指导。

所以说我有以下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>
...
...

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

  • 人员表(姓名,年龄)
  • somethingelse table(id)
  • 评论表(comment_id,comment_text)

我最终获得的是:

  • 人员表(person_Id&lt; - 内部SSIS ID)
  • 名表
  • 姓氏表
  • 年龄表
  • person_name table
  • person_surname table
  • person_comment_comment_id table

等...

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

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

似乎SSIS XML源需要一个非常一致的XML文件,意思是:如果 name 元素位于第1位,那么 name 元素>人父母必须在第1位。

如果某个中某些元素缺失到另一个,如果他们的排序不正确(A,B,C)(A,B,C),则SSIS似乎会解决不一致问题(A,C,B),它会大惊小怪!

感谢所有帮助!提前谢谢。

2 个答案:

答案 0 :(得分: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>

答案 1 :(得分:2)

如果您不想包含如何订购的手动定义,您可以按字母顺序排序。

<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>

这样输出顺序是可预测且稳定的,但<name>例如会在<comment>之后的中间某处结束。我不知道SSIS是否完全正确,但我想它应该是。


编辑:如果你想将依赖表(即包含子项而不是文本的元素)排序到底部......那么,<xsl:sort>可以多次应用。

  <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>

boolean(*)有效地将“儿童”/“没有儿童”的事实转换为true / false,而data-type="number" / 0反过来(在数字背景下,归因于1)表示为{{1}} / {{1}}。这样,纯文本元素就会在其他所有元素之前结束。