如何在父元素<element>可能具有子元素<element>的层次结构中使用xslt,这需要不同的逻辑</element> </element>

时间:2015-04-16 15:23:36

标签: xml xslt

所以我正在处理一个xml文档,其结构与此类似

原始XML:

普通元素

<element name="Name1">
  <document>
    <number>A1</number>
    <reference>B1</reference>
  </document>
</element>

类似于分组的元素 (为清楚起见,添加了根元素)

<root>
<element name="Name2.Group" id="Name2.xxx.Group">
   <element name="Name3">
    <document>
      <number>A2</number>
      <reference>B2</reference>
    </document>
  </element>
  <element name="Name4">
    <document>
      <number>A3</number>
      <reference>B3</reference>
    </document>
  </element>
</element>
</root>

我想从这份文件中得到的是这样的

<references>
  <reference>
    <original>A1</original>
    <mapping>B1</mapping>
  </reference>
 <reference>
  <group id="Name2.xxx.Group">
    <reference>
        <original>A2</original>
        <mapping>B2</mapping>
      </reference>
      <reference>
        <original>A3</original>
        <mapping>B3</mapping>
      </reference>
    </group>
  </reference>
</references>

我很难想出一个很好的方法来做到这一点,因为匹配元素似乎匹配所有元素。

到目前为止,我有这个,但意识到它不会起作用,因为父元素和一个元素具有相同的名称,但每个都需要一些不同的逻辑

<xsl:template match="/">
    <xsl:element name="references">
        <xsl:apply-templates select="@*|node()"/>
    </xsl:element>
</xsl:template>
<xsl:template match="element">
    <xsl:element name="reference">
        <xsl:if test="element/document">
            <xsl:element name="original">
                <xsl:value-of select="element/document/number"/>
            </xsl:element>
            <xsl:element name="mapping">
                <xsl:value-of select="element/document/reference"/>
            </xsl:element>
            <xsl:element name="id">
                <xsl:value-of select="@id"/>
            </xsl:element>
        </xsl:if>
    </xsl:element>
</xsl:template>

2 个答案:

答案 0 :(得分:1)

很难准确回答您的问题,因为您的第二个输入示例不是格式良好的XML(没有单个根元素),并且您的输出显示来自两个输入示例的数据。

以下样式表:

XSLT 1.0

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

<xsl:template match="/root">
    <references>
        <xsl:apply-templates/>
    </references>
</xsl:template>

<xsl:template match="element[@id]">
    <group id="{@id}">
        <xsl:apply-templates/>
    </group>
</xsl:template>

<xsl:template match="element">
    <reference>
        <original>
            <xsl:value-of select="document/number"/>
        </original>
        <mapping>
            <xsl:value-of select="document/reference"/>     
        </mapping>
    </reference>
</xsl:template>

</xsl:stylesheet>

应用于您的第一个输入示例时,将返回:

<?xml version="1.0" encoding="UTF-8"?>
<reference>
   <original>A1</original>
   <mapping>B1</mapping>
</reference>

应用于输入的以下更正示例时:

<root>
 <element name="Name2.Group" id="Name2.xxx.Group">
   <element name="Name3">
    <document>
      <number>A2</number>
      <reference>B2</reference>
    </document>
  </element>
  <element name="Name4">
    <document>
      <number>A3</number>
      <reference>B3</reference>
    </document>
  </element>
</element>
</root>

结果将是:

<?xml version="1.0" encoding="UTF-8"?>
<references>
   <group id="Name2.xxx.Group">
      <reference>
         <original>A2</original>
         <mapping>B2</mapping>
      </reference>
      <reference>
         <original>A3</original>
         <mapping>B3</mapping>
      </reference>
   </group>
</references>

答案 1 :(得分:1)

这种任务的规范方法是应用身份转换并对输出中应该看起来不同的节点进行修改。

<xsl:transform 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="*" />

    <!-- identity transform - copy everything unless another template fits -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>

    <!-- the document element becomes <references> -->
    <xsl:template match="/*">
        <references>
            <xsl:apply-templates select="@*|node()" />
        </references>
    </xsl:template>

    <!-- <element> becomes <reference> -->
    <xsl:template match="element">
        <reference>
            <xsl:apply-templates select="@*|node()" />
        </reference>
    </xsl:template>

    <!-- <element> with group becomes <group> -->
    <xsl:template match="element[contains(@name, '.Group')]">
        <group>
            <xsl:apply-templates select="@*|node()" />
        </group>
    </xsl:template>

    <!-- we don't want to see element/@name in the output -->
    <xsl:template match="element/@name" /> 

    <!-- <document> is stepped over (just process the children) -->
    <xsl:template match="element/document">
        <xsl:apply-templates select="@*|node()" />
    </xsl:template>

    <!-- <number> becomes <original> -->
    <xsl:template match="element/*/number">
        <original>
            <xsl:apply-templates select="@*|node()" />
        </original>
    </xsl:template>

    <!-- <reference> becomes <mapping> -->
    <xsl:template match="element/*/reference">
        <mapping>
            <xsl:apply-templates select="@*|node()" />
        </mapping>
    </xsl:template>
</xsl:transform>

输出,当应用于

<x>
    <element name="Name1">
      <document>
        <number>A1</number>
        <reference>B1</reference>
      </document>
    </element>
    <element name="Name2.Group" id="Name2.xxx.Group">
       <element name="Name3">
        <document>
          <number>A2</number>
          <reference>B2</reference>
        </document>
      </element>
      <element name="Name4">
        <document>
          <number>A3</number>
          <reference>B3</reference>
        </document>
      </element>
    </element>    
</x>

将是

<references>
   <reference>
      <original>A1</original>
      <mapping>B1</mapping>
   </reference>
   <group id="Name2.xxx.Group">
      <reference>
         <original>A2</original>
         <mapping>B2</mapping>
      </reference>
      <reference>
         <original>A3</original>
         <mapping>B3</mapping>
      </reference>
   </group>
</references>