首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用xslt合并和重新排列xml

使用xslt合并和重新排列xml
EN

Stack Overflow用户
提问于 2012-05-29 13:55:26
回答 2查看 252关注 0票数 1

我正在使用XSLT来转换从web派生的XML,并将其动态转换为表示为输出的目标xml文件。我仍然无法做到,即使尝试了很多,谁能帮我解决这个转换。

源XML

代码语言:javascript
运行
复制
<allocelement>
    <hd1>12</hd1>
    <hd2>14</hd2>
    <hd3>87</hd3>
        <alc>1</alc>
    <amount>4587</amount>
    <code>1111</code>
</allocelement>
<alloclement>
        <hd1>12</hd1>
    <hd2>14</hd2>
    <hd3>87</hd3>
    <alc>2</alc>
    <amount>80000</amount>
    <code>1111</code>
</alloclement>
<alloclement>
    <hd1>875</hd1>
    <hd2>455</hd2>
    <hd3>455</hd3>
    <alc>2</alc>
    <amount>80000</amount>
    <code>1112</code>
 </alloclement>

输出所需

代码语言:javascript
运行
复制
<allocelement>
    <Codeheader>
    <code>1111</code>
        <hd1>12</hd1>
        <hd2>14</hd2>
        <hd3>87</hd3>
                <alc>1</alc>
                    <amount>4587</amount>
                <alc>2</alc>
                    <amount>80000</amount>
    </codeHeader>
        <CodeHeader>
    <code>1112</code>
        <hd1>875</hd1>
        <hd2>455</hd2>
        <hd3>455</hd3>
            <alc>2</alc>
              <amount>80000</amount>
    </CodeHeader>
</allocelement>

分组以代码、hd1、hd2、hd3为基础,使得在其中具有相同代码的不同元素和hd1、hd2、hd3将被合并,并且只显示不同的字段。和。另外,我正在使用XSLT1.0。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-05-30 04:05:54

一个更短、更简单的XSLT1.0解决方案

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

 <xsl:key name="kCodeByVal" match="code" use="."/>

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

<xsl:template match="allocelement"/>

 <xsl:template match=
  "allocelement
    [generate-id(code) = generate-id(key('kCodeByVal', code)[1])]">
  <code><xsl:value-of select="code"/>
    <xsl:copy-of select=
    "node()[not(self::code)]
    | key('kCodeByVal', code)/../*[self::alc or self::amount]"/>
  </code>
 </xsl:template>
</xsl:stylesheet>

将此转换应用于以下XML文档(封装所提供的XML片段的单个顶部元素):

代码语言:javascript
运行
复制
<t>
    <allocelement>
        <hd1>12</hd1>
        <hd2>14</hd2>
        <hd3>87</hd3>
        <alc>1</alc>
        <amount>4587</amount>
        <code>1111</code>
    </allocelement>
    <allocelement>
        <hd1>12</hd1>
        <hd2>14</hd2>
        <hd3>87</hd3>
        <alc>2</alc>
        <amount>80000</amount>
        <code>1111</code>
    </allocelement>
    <allocelement>
        <hd1>875</hd1>
        <hd2>455</hd2>
        <hd3>455</hd3>
        <alc>2</alc>
        <amount>80000</amount>
        <code>1112</code>
    </allocelement>
</t>

想要的,正确的结果产生

代码语言:javascript
运行
复制
<allocelement>
   <code>1111<hd1>12</hd1>
      <hd2>14</hd2>
      <hd3>87</hd3>
      <alc>1</alc>
      <amount>4587</amount>
      <alc>2</alc>
      <amount>80000</amount>
   </code>
   <code>1112<hd1>875</hd1>
      <hd2>455</hd2>
      <hd3>455</hd3>
      <alc>2</alc>
      <amount>80000</amount>
   </code>
</allocelement>

解释性门窗分组法的正确使用。

XSLT2.0解决方案--同样更短,更重要的是--语法和语义上正确的

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

  <xsl:template match="/*">
  <allocelement>
   <xsl:for-each-group select="*" group-by="code">
     <code><xsl:value-of select="code"/>
        <xsl:sequence select=
        "node()[not(self::code)]
        | current-group()/*[self::alc or self::amount]"/>
  </code>
   </xsl:for-each-group>
  </allocelement>
 </xsl:template>
</xsl:stylesheet>

UPDATE:OP已经更改了outpu的需求。

这里是相应的修改的XSLT1.0解决方案

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

     <xsl:key name="kCodeByVal" match="code" use="."/>

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

    <xsl:template match="allocelement"/>

     <xsl:template match=
      "allocelement
        [generate-id(code) = generate-id(key('kCodeByVal', code)[1])]">
      <codeHeader>
       <code><xsl:value-of select="code"/></code>
         <xsl:copy-of select=
         "node()[not(self::code)]
         | key('kCodeByVal', code)/../*[self::alc or self::amount]"/>
      </codeHeader>
     </xsl:template>
</xsl:stylesheet>
票数 0
EN

Stack Overflow用户

发布于 2012-05-29 14:14:07

我假设您的输入XML有一个root节点,它封装所有这些以生成一个格式良好的文档。我还假设所有的allocelement都拼写正确(有些拼写为alloclement)。我还假设您希望删除标记名称及其文本值所标识的重复项。

使用XSLT1.0

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

    <xsl:key name="code" match="allocelement/code" use="."/>

    <xsl:key name="code-sibling" 
             match="allocelement/*[name() != 'code']" 
             use="concat(parent::*/code, '|', name(), '|', .)"/>

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

    <xsl:template match="/">
        <xsl:apply-templates select="root/allocelement[1]"/>
    </xsl:template>

    <xsl:template match="allocelement">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates 
                    select="(. | following-sibling::allocelement)/code
                                [generate-id() = generate-id(key('code', .)[1])]"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="code">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:value-of select="."/>

            <xsl:apply-templates 
                    select="key('code', .)/(preceding-sibling::* | following-sibling::*)
                                [generate-id() = 
                                 generate-id(key('code-sibling', concat(parent::*/code, '|', name(), '|', .))[1])]"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

适用于:

代码语言:javascript
运行
复制
<root>
    <allocelement>
        <hd1>12</hd1>
        <hd2>14</hd2>
        <hd3>87</hd3>
        <alc>1</alc>
        <amount>4587</amount>
        <code>1111</code>
    </allocelement>
    <allocelement>
        <hd1>12</hd1>
        <hd2>14</hd2>
        <hd3>87</hd3>
        <alc>2</alc>
        <amount>80000</amount>
        <code>1111</code>
    </allocelement>
    <allocelement>
        <hd1>875</hd1>
        <hd2>455</hd2>
        <hd3>455</hd3>
        <alc>2</alc>
        <amount>80000</amount>
        <code>1112</code>
     </allocelement>
</root>

生产:

代码语言:javascript
运行
复制
<root>
   <allocelement>
      <code>1111<hd1>12</hd1>
         <hd2>14</hd2>
         <hd3>87</hd3>
         <alc>1</alc>
         <amount>4587</amount>
         <alc>2</alc>
         <amount>80000</amount>
      </code>
      <code>1112<hd1>875</hd1>
         <hd2>455</hd2>
         <hd3>455</hd3>
         <alc>2</alc>
         <amount>80000</amount>
      </code>
   </allocelement>
</root>

这就是它的工作原理。默认路由是同一性变换。我们首先中断allocelement并将转换发送到另一条路径。我们让它用它的值复制唯一的code元素(由元素的文本值标识的唯一性),然后将模板应用到所有共享相同值的code节点的前面/后面的兄弟节点上。现在,这些将是code节点的子节点。然后,我们为唯一的兄弟姐妹调用身份转换(属于相同值的code,具有相同的名称和相同的文本值)。

一个音符。混合含量从来不是一个好主意。查看是否确实需要混合code下的文本值和子节点。

使用XSLT2.0,您可以远离generate-id()

代码语言:javascript
运行
复制
<xsl:template match="allocelement">
    <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <xsl:for-each-group select="(. | following-sibling::allocelement)/code" group-by=".">
            <xsl:apply-templates select="."/>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>

<xsl:template match="code">
    <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <xsl:value-of select="."/>

        <xsl:for-each-group select="key('code', .)/(preceding-sibling::* | following-sibling::*)"
                            group-by="concat(parent::*/code, '|', name(), '|', .)">
            <xsl:apply-templates select="."/>
        </xsl:for-each-group> 
    </xsl:copy>
</xsl:template>
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10800627

复制
相关文章

相似问题

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