具有相同级别下重复节点的 XSLT 变换

Posted

技术标签:

【中文标题】具有相同级别下重复节点的 XSLT 变换【英文标题】:XSLT transform with repeating node under same level 【发布时间】:2021-10-05 02:36:10 【问题描述】:

我是 xslt 的新手。我正在学习 xslt 并且难以转换 xml 格式。 我有以下 xml 输入

```<Body>
    <Grp Name="Root">
      <Grp Name="Info">
        <Parm Name="parent_id" Val="Id_1" />
        <Grp Name="CurrenInfo">
          <Parm Name="current_id" Val="Id_1A" />
          <Grp Name="CurrentChildInfo">
            <Parm Name="Name" Val="State1" />
            <Parm Name="Value" Val="S1" />
          </Grp>
          <Grp Name="CurrentChildInfo">
            <Parm Name="Name" Val="State2" />
            <Parm Name="Value" Val="S2" />
          </Grp>
        </Grp>
        <Grp Name="CurrenInfo">
          <Parm Name="current_id" Val="Id_1B" />
          <Grp Name="CurrentChildInfo">
            <Parm Name="Name" Val="State3" />
            <Parm Name="Value" Val="S3" />
          </Grp>
        </Grp>
      </Grp>
    </Grp>
  </Body>`

我需要将其转换为以下格式.....

```<Info>
  <parent_id>Id_1</parent_id>
  <original_list>
    <list>
      <current_id>Id_1A</current_id>
      <Name>State1</Name>
      <Value>S1</Value>
     </list>
     <list>
      <current_id>Id_1A</current_id>
      <Name>State2</Name>
      <Value>S2</Value>
    </list>
    <list>
      <current_id>Id_1B</current_id>
      <Name>State3</Name>
      <Value>S3</Value>
    </list>
  </original_list>
<Info>```

以下是我目前的 xslt

```<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
  
  <xsl:template match="Body">
        <xsl:element name="Info">
          <xsl:for-each select="//Grp[@Name='Root']/Grp[@Name='Info']">
            <xsl:for-each select="Parm">
              <xsl:element name="parent_id">
                <xsl:value-of select="@Val"/>
              </xsl:element>
            </xsl:for-each>
              <xsl:for-each select="//Grp[@Name='CurrenInfo']">
                <xsl:element name="list">
                  <xsl:for-each select="Parm">
                    <xsl:element name="current_id">
                      <xsl:value-of select="@Val"/>
                    </xsl:element>
                  </xsl:for-each>
                    <xsl:for-each select="Grp[@Name='CurrentChildInfo']">
                        <xsl:for-each select="Parm">
                          <xsl:element name="@Name">
                            <xsl:value-of select="@Val"/>
                          </xsl:element>
                        </xsl:for-each>
                    </xsl:for-each>
                  </xsl:element>
              </xsl:for-each>
          </xsl:for-each>
        </xsl:element>
  </xsl:template>
</xsl:stylesheet>```

但是当我使用上面的 xslt 时输出格式如下

```<Info>
  <parent_id>Id_1</parent_id>
  <list>
    <current_id>Id_1A</current_id>
    <Name>State1</Name>
    <Value>S1</Value>
    <Name>State2</Name>
    <Value>S2</Value>
  </list>
  <list>
    <current_id>Id_1B</current_id>
    <Name>State3</Name>
    <Value>S3</Value>
  </list>
</Info>```

需要帮助来纠正 xslt 以返回所需的格式 谢谢

【问题讨论】:

【参考方案1】:

只做一些小的修改,你可以使用下面的样式表:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
    
    <xsl:template match="Body">
        <xsl:element name="Info">
            <xsl:for-each select="Grp[@Name='Root']/Grp[@Name='Info']">
                <xsl:for-each select="Parm">
                    <xsl:element name="parent_id">
                        <xsl:value-of select="@Val"/>
                    </xsl:element>
                </xsl:for-each>
                <original_list>
                    <xsl:for-each select=".//Grp[@Name='CurrentChildInfo']">
                        <xsl:element name="list">
                            <xsl:for-each select="../Parm">
                                <xsl:element name="current_id">
                                    <xsl:value-of select="@Val"/>
                                </xsl:element>
                            </xsl:for-each>
                            <xsl:for-each select="Parm">
                                <xsl:element name="@Name">
                                    <xsl:value-of select="@Val"/>
                                </xsl:element>
                            </xsl:for-each>
                        </xsl:element>
                    </xsl:for-each>
                </original_list>
            </xsl:for-each>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

它的输出是

<Info>
   <parent_id>Id_1</parent_id>
   <original_list>
      <list>
         <current_id>Id_1A</current_id>
         <Name>State1</Name>
         <Value>S1</Value>
      </list>
      <list>
         <current_id>Id_1A</current_id>
         <Name>State2</Name>
         <Value>S2</Value>
      </list>
      <list>
         <current_id>Id_1B</current_id>
         <Name>State3</Name>
         <Value>S3</Value>
      </list>
   </original_list>
</Info>

我从第一个xsl:for-each 中删除了//,因为它似乎没有必要。但如果你想选择所有@Name='Root' 孩子,最好使用.//

【讨论】:

非常感谢。它按预期工作..祝你有美好的一天 我确实想知道这种答案是否 OP 真的理解了为什么他们的代码不起作用,并且会避免再次犯同样的错误。 嗨 MK,我明白我原来代码中的错误,谢谢你的关心..

以上是关于具有相同级别下重复节点的 XSLT 变换的主要内容,如果未能解决你的问题,请参考以下文章

如何合并具有“相同父亲”、相同方法和相同 id=0 的两个节点(使用 XSLT)?

如何合并具有“相同父亲”和具有精确“方法”序列的两个节点(使用 XSLT)?

使用 XSLT 组合具有相同 ID 及其值的节点 (XML)

矩阵的秩--上--中--下

如何获取具有相同名称的元素并根据 XSLT 中的子节点值对它们进行排序

XSLT 用子节点重复父节点