【问题标题】:need help in transforming XML to XML using XSL在使用 XSL 将 XML 转换为 XML 方面需要帮助
【发布时间】:2013-02-26 10:58:21
【问题描述】:

好的,我正在编辑原始帖子。我想我通过替换原始 XML 的名称标签做了很多尝试。无论如何,这是原始文件的摘录:

<EMPLOYEE_LIST>
   <EMPLOYEES>
      <EMPLOYEE>
         <EMPID>650000</EMPID>
         <FIRST_NAME>KEITH</FIRST_NAME>
         <MIDDLE_NAME>HUTCHINSON</MIDDLE_NAME>
         <LAST_NAME>ROGERS</LAST_NAME>
         <EMP_TYPE></EMP_TYPE>
         <EMP_REF_ID>500000</EMP_REF_ID>
         <JOINED_ON>2001-10-06</JOINED_ON>
         <COMMENTS>Miscellanous Comments</COMMENTS>
         <NATIONALITY>
            <VALUE>American</VALUE>
         </NATIONALITY>
         <EMP_AKA>
            <AKA_NAME>Danny</AKA_NAME>
         </EMP_AKA>
         <EMP_AKA>
            <AKA_NAME>Dan</AKANAME>
         </EMP_AKA>
         <EMP_AKA>
            <AKA_NAME>Ray</AKA_NAME>
         </EMP_AKA>
         <EMP_ADDR>
            <STREET> </STREET>
            <CITY> </CITY>
            <STATE> </STATE>
            <ZIP> </ZIP>
            <COUNTRY> </COUNTRY>
       </EMPLOYEE>
    </EMPLOYEES>
</EMPLOYEE_LIST>

我在使用上述 XML 时遇到的问题是,我无法找到一种方法将多个 AKA(也称为)属性放在一个属性下,而我用于此转换的 XSL 如下:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
        <xsl:template match="/EMPLOYEE_LIST">
            <employees>
                <xsl:apply-templates select="EMPLOYEES/node()"/>
            </employees>        
        </xsl:template>

        <xsl:template match="EMPLOYEE">
        <employee>
            <xsl:apply-templates select="*"/>
        </employee>
        </xsl:template>

        xsl:template match="EMPLOYEE/EMPID">
        <emp_id>
            <xsl:value-of select="."/>
        </emp_id>
        </xsl:template>

            <xsl:template match="EMPLOYEE/FIRST_NAME">
        <f_name>
            <xsl:value-of select="."/>
        </f_name>
        </xsl:template>

        <xsl:template match="EMPLOYEE/MIDDLE_NAME">
            <m_name>
                <xsl:value-of select="."/>
            </m_name>
        </xsl:template>

        <xsl:template match="EMPLOYEE/LAST_NAME">
            <l_name>
                <xsl:value-of select="."/>
            </l_name>
        </xsl:template>
        .
        .
        .
        .
        .
        <xsl:template match="EMPLOYEE/EMP_AKA">
        <aka_list>
            <xsl:for-each select="AKA_NAME">
                <aka>
                    <xsl:for-each select=".">
                        <xsl:apply-templates/>
                    </xsl:for-each>
                </aka>
            </xsl:for-each>
        </aka_list>
     </xsl:template>
</xsl:stylesheet>

当应用到我的 XML 时,上面给出的 XSL 给出了以下输出:

<?xml version="1.0" encoding="UTF-8"?>
<employees>
      <employee>
         <emp_id>111345</emp_id>
         <f_name>KEITH</f_name>
         <m_name>HUTCHINSON</m_name>
         <l_name>ROGERS</l_name>
         <aka_list>
            <aka>Danny</aka>
         </aka_list>
         <aka_list>
            <aka>Dan</aka>
         </aka_list>
         <aka_list>
            <aka>Ray</aka>
         </aka_list>
      </employee>
</employees>

这不是我想要实现的目标,因为我需要以下格式的数据:

<?xml version="1.0" encoding="UTF-8"?>
<employees>
      <employee>
         <emp_id>111345</emp_id>
         <f_name>KEITH</f_name>
         <m_name>HUTCHINSON</m_name>
         <l_name>ROGERS</l_name>
         <aka_list>
            <aka>Danny</aka>
            <aka>Dan</aka>
            <aka>Ray</aka>
         </aka_list>
      </employee>
</employees

有什么办法可以做到吗?

展望未来,XML 中的元素数量巨大,例如 AKA_NAME。

         <aka_list>
            <aka>Danny</aka>
         </aka_list>
         <aka_list>
            <aka>Dan</aka>
         </aka_list>
         <aka_list>
            <aka>Ray</aka>
         </aka_list>
         <aka_list>
            <aka>Danny_2</aka>
         </aka_list>
         <aka_list>
            <aka>Dan_2</aka>
         </aka_list>
         <aka_list>
            <aka>Ray_2</aka>
         </aka_list>

转换应该只继承前5个,第六个应该被截断,如:

         <aka_list>
            <aka>Danny</aka>
            <aka>Dan</aka>
            <aka>Ray</aka>
            <aka>Danny_2</aka>
            <aka>Dan_2</aka>
         </aka_list>

【问题讨论】:

  • 您发布的输出与 XSLT 模板不匹配(输出中没有 AKA_LIST 元素)。
  • &lt;AKA&gt;JOHN FILTER&lt;/ALIAS&gt; opens with AKA closes with ALIAS, 验证错误.. 请确保您输入的 XML。
  • 我不明白,您的代码中有&lt;AKA_LIST&gt;,但输出中有&lt;PEOPLE&gt;&lt;PERSON&gt;?你到底想要哪一个??
  • 用来源编辑了原帖

标签: xml xslt


【解决方案1】:

更新:完整 XML 的解决方案。

我尝试在 XSLT 模板中使用 cmets 解释解决方案。

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

    <!-- Ignore text nodes by default -->
    <xsl:template match="text()" />

    <!-- Transform tag name EMPLOYEES to employees -->
    <xsl:template match="EMPLOYEES">
        <employees>
            <xsl:apply-templates select="*" />
        </employees>
    </xsl:template>

    <!-- Transform tag name EMPLOYEE to employee -->
    <xsl:template match="EMPLOYEE">
        <employee>
            <xsl:apply-templates select="*" />
        </employee>
    </xsl:template>

    <!-- Transform tag name EMPID to emp_id -->
    <xsl:template match="EMPID">
        <emp_id>
            <xsl:value-of select="." />
        </emp_id>
    </xsl:template>

    <!-- Transform tag name FIRST_NAME to f_name -->
    <xsl:template match="FIRST_NAME">
        <f_name>
            <xsl:value-of select="." />
        </f_name>
    </xsl:template>

    <!-- Transform tag name MIDDLE_NAME to m_name -->
    <xsl:template match="MIDDLE_NAME">
        <m_name>
            <xsl:value-of select="." />
        </m_name>
    </xsl:template>

    <!-- Transform tag name LAST_NAME to l_name -->
    <xsl:template match="LAST_NAME">
        <l_name>
            <xsl:value-of select="." />
        </l_name>
    </xsl:template>

    <!-- When encounter the first EMP_AKA element, print itself and its following
         siblings with the same name within an aka_list element -->
    <xsl:template match="EMP_AKA[1]">
        <aka_list>
            <xsl:apply-templates select="AKA_NAME|following-sibling::EMP_AKA/AKA_NAME" mode="print"/>
        </aka_list>
    </xsl:template>

    <!-- Transform tag name EMP_AKA to aka -->
    <xsl:template match="AKA_NAME" mode="print">
        <aka>
            <xsl:value-of select="." />
        </aka>  
    </xsl:template>

</xsl:stylesheet>

更新 2:如果您不想使用模板模式,因为 AKA_NAME 将在其他地方匹配并以相同方式处理,您可以将最后两个模板替换为以下模板:

<!-- When encounter the first EMP_AKA element, print itself and its following
     siblings with the same name within an aka_list element -->
<xsl:template match="EMP_AKA[1]">
    <aka_list>
        <xsl:apply-templates select="AKA_NAME|following-sibling::EMP_AKA/AKA_NAME" />
    </aka_list>
</xsl:template>

<!-- Exclude all EMP_AKA elements (except the first one because
     the previous template has higher precedence than this one) -->
<xsl:template match="EMP_AKA" />

<!-- Transform tag name EMP_AKA to aka -->
<xsl:template match="AKA_NAME">
    <aka>
        <xsl:value-of select="." />
    </aka>  
</xsl:template>

<xsl:template match="EMP_AKA" />

此代码产生与前一个相同的输出。


更新 3:OP 询问如何限制输出的 AKA_NAME 元素的数量。这是基于 UPDATE 2 的解决方案。只需将 UPDATE 2 中的最后一个模板替换为

<xsl:template match="EMP_AKA[1]">
    <aka_list>
        <xsl:apply-templates select="AKA_NAME|following-sibling::EMP_AKA[position() &lt; 5]/AKA_NAME" />
    </aka_list>
</xsl:template>

<!-- Transform tag name EMP_AKA to aka -->
<xsl:template match="AKA_NAME">
    <aka>
        <xsl:value-of select="." />
    </aka>  
</xsl:template>

<xsl:template match="EMP_AKA" />

原始答案

OP 编辑​​了帖子并完全更改了 XML 文件。以下是我之前的答案(删除它似乎不正确)。

如果您尝试将所有 元素组合成一个 元素(不清楚,因为您发布的输出与转换不匹配),那么您可以使用以下转换:

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

    <!-- Just for demo -->
    <xsl:template match="text()" />

    <!-- Match PERSON: create the list -->
    <xsl:template match="PERSON">
        <AKA_LIST>
            <xsl:apply-templates select="NAME/AKA" />
        </AKA_LIST>
    </xsl:template> 

    <!-- Outputs the AKA element, changing the tag name -->
    <xsl:template match="AKA">
        <aka>
            <xsl:value-of select="." />
        </aka>
    </xsl:template>

</xsl:stylesheet>

您将 XML 源转换成哪种转换:

<AKA_LIST>
   <aka>ROSE PETAL</aka>
   <aka>JOHN FILTER</aka>
</AKA_LIST>

【讨论】:

  • 不错的解决方案 Pablo,仅使用模板匹配和应用模板。 +1
  • &lt;xsl:template match="AKA"&gt; 不需要.. 因为它不是重命名的要求.. 还有一个更好的做法是覆盖身份模板..
  • 好吧,直到 OP 在他的帖子中阐明他想要做什么,我们才会知道这一点。我对他正在尝试做的事情做了一个假设,并为此发布了解决方案。我不认为我们可以假设是否需要重命名(想象他将在此之后使用 XML Schema 来验证输出 XML)
  • 您可以创建一个聊天室,这样我们就可以在那里交谈。请告诉我聊天室的名称。
  • @PabloPozo 谢谢你的解决方案。另一个简单的问题:在某些情况下,一个节点有大量的 aka 属性(给定一个员工有 2 个属性的源)。有没有一种方法可以将它们限制为 5,而不管它们在原始 XML 中的数量是多少?
【解决方案2】:

您的 XSLT 代码实际上令人困惑,因为您有一些标签,例如 &lt;AKA_LIST&gt;。所以我要输入和输出 XML 示例:这里是 XSLT 代码

<?xml version="1.0" encoding="utf-8"?>
<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="NAME[1]"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="NAME">
    <xsl:copy>
      <xsl:apply-templates select="/PEOPLE/PERSON/NAME/AKA"/>
    </xsl:copy>
  </xsl:template>


</xsl:stylesheet>

输入 XML:

<?xml version="1.0" encoding="utf-8"?>
<PEOPLE>
  <PERSON>
    <NAME>
      <REFERENCE>GOOD</REFERENCE>
      <AKA>ROSE PETAL</AKA>
      </NAME>
    <NAME>
      <REFERENCE>GOOD</REFERENCE>
      <AKA>JOHN FILTER</AKA>
      </NAME>
  </PERSON>
</PEOPLE>

输出:

<?xml version="1.0" encoding="utf-8"?>
<PEOPLE>
  <PERSON>
    <NAME>
      <AKA>ROSE PETAL</AKA>
      <AKA>JOHN FILTER</AKA>
    </NAME>
  </PERSON>
</PEOPLE>

说明:

<xsl:template match="@*|node()"> ......

上面的代码将标签从输入复制到输出AS IS*,其他模板匹配覆盖这个..

<xsl:template match="PERSON"> ......

以上代码仅将一个&lt;NAME&gt; TAG(第一个)复制到输出中。

<xsl:template match="NAME">
    <xsl:copy>
      <xsl:apply-templates select="/PEOPLE/PERSON/NAME/AKA"/>
      ......

上述代码复制所有 &lt;AKA&gt; 标签下 &lt;NAME&gt;。由于我们只复制了一个&lt;NAME&gt; 标签,所有&lt;AKA&gt; 标签都出现在&lt;NAME&gt;

【讨论】:

    猜你喜欢
    • 2021-11-06
    • 2012-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多