首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用XSLT和一个键对SQL Server产生的XML进行规范化

如何使用XSLT和一个键对SQL Server产生的XML进行规范化
EN

Stack Overflow用户
提问于 2013-01-02 10:26:28
回答 1查看 811关注 0票数 1

当我以XML形式从SQL Server查询数据时,通常会生成重复的XML节点。我经常可以调整查询来消除这一点,但并不总是如此。对于那些我做不到的时候,我最终会使用这样的XML:

代码语言:javascript
复制
<Xml>
<House houseId="3" address="123 Main">
    <Dog dogId="13" name="Rover">
        <Flea fleaId="17" name="Chester" />
    </Dog>
    <Dog dogId="13" name="Rover">
        <Flea fleaId="23" name="Poindexter" />            
    </Dog>
</House>
<House houseId="3" address="123 Main">
    <Human humanId="9" name="Mr. Johnson">
        <Child childId="11" name="Susie" />
    </Human>
    <Human humanId="9" name="Mr. Johnson">
        <Child childId="31" name="Sandy" />
    </Human>
</House>
<House houseId="5" address="987 Wall">
    <Dog dogId="13" name="Rover">
        <Flea fleaId="17" name="Chester" />
    </Dog>
    <Dog dogId="13" name="Rover">
        <Flea fleaId="19" name="Wilhelm" />            
    </Dog>
</House>
</Xml>

请注意,有两个相邻的节点,它们的属性相同。它们的不同之处仅在于它们的子节点。我正在尝试创建一个XSLT,它将采用相同的同级节点,并将它们折叠成一个包含所有子节点的超集的节点。在本例中,将同时包含和节点。如下所示:

代码语言:javascript
复制
<Xml>
<House houseId="3" address="123 Main">
    <Dog dogId="13" name="Rover">
        <Flea fleaId="17" name="Chester" />
        <Flea fleaId="23" name="Poindexter" />            
    </Dog>
    <Human humanId="9" name="Mr. Johnson">
        <Child childId="11" name="Susie" />
        <Child childId="31" name="Sandy" />
    </Human>
</House>
<House houseId="5" address="987 Wall">
    <Dog dogId="13" name="Rover">
        <Flea fleaId="17" name="Chester" />
        <Flea fleaId="19" name="Wilhelm" />            
    </Dog>
</House>
</Xml>

不仅合并了两个相同的House节点,还合并了duplicate Dog和Human节点。但请注意,列出在两个不同节点下的节点并未组合,因为它们并不相同。(由于他们的祖先。)这就是我要做的:组合匹配的同级节点。

因为XML是由SQL生成的,所以XSLT将处理许多不同名称和排列的节点。因此,我不能对节点名称进行硬编码。但我可以肯定的是,每个节点都会有一个相应的id属性,其中包含一个数值。例如:、和。

我还知道根节点将没有属性,因此我可以开始处理根节点的子节点。

我的策略是为每个Node创建一个xsl:key,其中节点的key-value是其祖先节点与id值的串联。示例键值在下面的注释中

代码语言:javascript
复制
<Xml>
<House houseId="3" address="123 Main"><!--"houseId=3"-->
    <Dog dogId="13" name="Rover" ><!--"houseId=3;dogId=13"-->
        <Flea fleaId="17" name="Chester" /><!--"houseId=3;dogId=13;fleaId=17"-->
    </Dog>
    <Dog dogId="13" name="Rover" ><!--"houseId=3;dogId=13"-->
        <Flea fleaId="23" name="Poindexter" /><!--"houseId=3;dogId=13;fleaId=23"-->         
    </Dog>
</House>
<House houseId="3" address="123 Main" ><!--"houseId=3"-->
    <Human humanId="9" name="Mr. Johnson" ><!--"houseId=3;humanId=9"-->
        <Child childId="11" name="Susie" /><!--"houseId=3;humanId=9;childId=11"-->
    </Human>
    <Human humanId="9" name="Mr. Johnson"><!--"houseId=3;humanId=9"-->
        <Child childId="31" name="Sandy" /><!--"houseId=3;humanId=9;childId=31"-->
    </Human>
</House>
<House houseId="5" address="987 Wall" ><!--"houseId=5"-->
    <Dog dogId="13" name="Rover"><!--"houseId=5;dogId=13"-->
        <Flea fleaId="17" name="Chester" /><!--"houseId=5;dogId=13;fleaId=17"-->
    </Dog>
    <Dog dogId="13" name="Rover"><!--"houseId=5;dogId=13"-->
        <Flea fleaId="19" name="Wilhelm" /><!--"houseId=5;dogId=13;fleaId=19"-->           
    </Dog>
</House>
</Xml>

因此,这两个看似匹配的事件将通过它们的祖先来区分:

houseId=3;dogId=13

houseId=5;dogId=13

这样,就可以组合重复的(同级)节点。不幸的是,我正在努力理解如何使用XSL和xslt:key来实现这一点。任何帮助都将不胜感激。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-01-02 11:41:01

此转换

代码语言:javascript
复制
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:my="my:my">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

 <xsl:template match="/*" priority="3">
  <xsl:sequence select="my:grouping(., *)"/>
 </xsl:template>

 <xsl:function name="my:grouping" as="element()*">
  <xsl:param name="pElem" as="element()"/>
  <xsl:param name="pChildren" as="element()*"/>

  <xsl:element name="{name($pElem)}" namespace="{namespace-uri($pElem)}">
   <xsl:apply-templates select="$pElem/@*"/>
   <xsl:for-each-group select="$pChildren" group-by="my:signature(.)">
     <xsl:copy>
       <xsl:apply-templates select="@*|node()[not(self::*)]"/>
       <xsl:apply-templates select=
           "my:grouping(., current-group()/*)/*"/>
     </xsl:copy>
   </xsl:for-each-group>
  </xsl:element>
 </xsl:function>

 <xsl:function name="my:signature" as="xs:string">
  <xsl:param name="pElem" as="element()"/>

  <xsl:variable name="vAttibs" as="xs:string*">
   <xsl:perform-sort select="$pElem/@*">
     <xsl:sort select="name()"/>
   </xsl:perform-sort>
  </xsl:variable>
  <xsl:sequence select=
   "string-join((name($pElem)
                 ,for $at in $vAttibs
                   return concat($at, '+', $pElem/@*[name()=$at])
                 )
                  ,'|')"/>
 </xsl:function>
</xsl:stylesheet>

在所提供的XML文档上应用时的

代码语言:javascript
复制
<Xml>
    <House houseId="3" address="123 Main">
        <Dog dogId="13" name="Rover">
            <Flea fleaId="17" name="Chester" />
        </Dog>
        <Dog dogId="13" name="Rover">
            <Flea fleaId="23" name="Poindexter" />
        </Dog>
    </House>
    <House houseId="3" address="123 Main">
        <Human humanId="9" name="Mr. Johnson">
            <Child childId="11" name="Susie" />
        </Human>
        <Human humanId="9" name="Mr. Johnson">
            <Child childId="31" name="Sandy" />
        </Human>
    </House>
    <House houseId="5" address="987 Wall">
        <Dog dogId="13" name="Rover">
            <Flea fleaId="17" name="Chester" />
        </Dog>
        <Dog dogId="13" name="Rover">
            <Flea fleaId="19" name="Wilhelm" />
        </Dog>
    </House>
</Xml>

会生成想要的正确结果:

代码语言:javascript
复制
<Xml>
   <House houseId="3" address="123 Main">
      <Dog dogId="13" name="Rover">
         <Flea fleaId="17" name="Chester"/>
         <Flea fleaId="23" name="Poindexter"/>
      </Dog>
      <Human humanId="9" name="Mr. Johnson">
         <Child childId="11" name="Susie"/>
         <Child childId="31" name="Sandy"/>
      </Human>
   </House>
   <House houseId="5" address="987 Wall">
      <Dog dogId="13" name="Rover">
         <Flea fleaId="17" name="Chester"/>
         <Flea fleaId="19" name="Wilhelm"/>
      </Dog>
   </House>
</Xml>

和这个扩展的文档(添加了文本节点):

代码语言:javascript
复制
<Xml>
    <House houseId="3" address="123 Main">
        <Dog dogId="13" name="Rover">
          Dog named Rover
            <Flea fleaId="17" name="Chester">Regular dog flee</Flea>
        </Dog>
        <Dog dogId="13" name="Rover">
            <Flea fleaId="23" name="Poindexter">Flea named Poindexter</Flea>
        </Dog>
    </House>
    <House houseId="3" address="123 Main">
        <Human humanId="9" name="Mr. Johnson">
            <Child childId="11" name="Susie">Susan Johnson</Child>
        </Human>
        <Human humanId="9" name="Mr. Johnson">
            <Child childId="31" name="Sandy">Sandy Johnson</Child>
        </Human>
    </House>
    <House houseId="5" address="987 Wall">
        <Dog dogId="13" name="Rover">
            <Flea fleaId="17" name="Chester" />
        </Dog>
        <Dog dogId="13" name="Rover">
            <Flea fleaId="19" name="Wilhelm" />
        </Dog>
    </House>
</Xml>

再次生成正确的结果

代码语言:javascript
复制
<Xml>
   <House houseId="3" address="123 Main">
      <Dog dogId="13" name="Rover">
          Dog named Rover
            <Flea fleaId="17" name="Chester">Regular dog flee</Flea>
         <Flea fleaId="23" name="Poindexter">Flea named Poindexter</Flea>
      </Dog>
      <Human humanId="9" name="Mr. Johnson">
         <Child childId="11" name="Susie">Susan Johnson</Child>
         <Child childId="31" name="Sandy">Sandy Johnson</Child>
      </Human>
   </House>
   <House houseId="5" address="987 Wall">
      <Dog dogId="13" name="Rover">
         <Flea fleaId="17" name="Chester"/>
         <Flea fleaId="19" name="Wilhelm"/>
      </Dog>
   </House>
</Xml>

说明

我们使用两个函数:my:signature()my:grouping()

  1. my:signature()为每个元素创建一个签名--这是元素名称的竖线分隔字符串,所有按attrName.
  2. my:grouping()排序的attrName+value对都使用my:signature()进行正确的分组。它有第二个参数,包含要分组的元素。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14116222

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档