XSLT转换根据存在的元素的最大计数动态添加空元素

时间:2016-05-27 14:36:26

标签: xml xslt

以下XML是我的输入

<?xml version="1.0" encoding="UTF-8"?>
<Item>
   <Description>
      <BB>Main1</BB>
      <CC>
         <DD>Content1</DD>
         <EE>
            <EE1>Answer1</EE1>
         </EE>
      </CC>
   </Description>
   <Description>
      <BB>Main2</BB>
      <CC>
         <DD>Content2</DD>
         <EE>
            <EE1>Answer2.1</EE1>
         </EE>
         <EE>
            <EE1>Answer2.2</EE1>
         </EE>
         <EE>
            <EE1>Answer2.3</EE1>
         </EE>
      </CC>
   </Description>
   <Description>
      <BB>Main3</BB>
      <CC>
         <DD>Content3</DD>
         <EE>
            <EE1>Answer3</EE1>
         </EE>
      </CC>
   </Description>
</Item>

节点EE的计数在所有CC父标签中应该相等(此计数是CC内EE的最大值)

在我的示例中,EE标记的最大计数为3.是否可以通过获取此计数来动态添加EE元素? 如果没有值,那么我将填充非破坏空白区域。 所以转换后我的xml应该是

<?xml version="1.0" encoding="UTF-8"?>
<Item>
   <Description>
      <BB>Main1</BB>
      <CC>
         <DD>Content1</DD>
         <EE>
            <EE1>Answer1</EE1>
         </EE>
         <EE>
            <EE2>       </EE2>
         </EE>
         <EE>
            <EE3>       </EE3>
         </EE>
      </CC>
   </Description>
   <Description>
      <BB>Main2</BB>
      <CC>
         <DD>Content2</DD>
         <EE>
            <EE1>Answer2.1</EE1>
         </EE>
         <EE>
            <EE2>Answer2.2</EE2>
         </EE>
         <EE>
            <EE3>Answer2.3</EE3>
         </EE>
      </CC>
   </Description>
   <Description>
      <BB>Main3</BB>
      <CC>
         <DD>Content3</DD>
         <EE>
            <EE1>Answer3</EE1>
         </EE>
         <EE>
            <EE2>       </EE2>
         </EE>
         <EE>
            <EE3>        </EE3>
         </EE>
      </CC>
   </Description>
</Item>

感谢任何帮助。 提前谢谢。

2 个答案:

答案 0 :(得分:3)

以这种方式尝试:

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:variable name="max-ee">
    <xsl:for-each select="/Item/Description/CC">
        <xsl:sort select="count(EE)" data-type="number" order="descending"/>
        <xsl:if test="position() = 1">
            <xsl:value-of select="count(EE)"/>
        </xsl:if>
    </xsl:for-each>
</xsl:variable>

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

<xsl:template match="CC">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
        <xsl:call-template name="gen-ee">
            <xsl:with-param name="i" select="count(EE)"/>
        </xsl:call-template>
    </xsl:copy>
</xsl:template>

<xsl:template name="gen-ee">
    <xsl:param name="i" />
    <xsl:if test="$i &lt; $max-ee">
        <EE/>
        <xsl:call-template name="gen-ee">
            <xsl:with-param name="i" select="$i +1"/>
        </xsl:call-template>        
    </xsl:if>
</xsl:template>

</xsl:stylesheet>

加了:

要在已修改问题中生成输出,请在最后一个模板中更改此行:

<EE/>

为:

<EE>
    <xsl:element name="EE{$i + 1}">&#160;</xsl:element>
</EE>

请注意,现有的EE1元素不会重新编号 - 尽管通过添加模板也可以做到这一点很简单:

<xsl:template match="EE1">
    <xsl:element name="EE{count(../preceding-sibling::EE) + 1}">
        <xsl:apply-templates />
   </xsl:element>
</xsl:template>

答案 1 :(得分:0)

以下是一个正确的解决方案

<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:variable name="vMax">
    <xsl:for-each select="/*/*/CC">
      <xsl:sort select="count(EE)" data-type="number" order="descending"/>
      <xsl:if test="position() = 1">
        <xsl:value-of select="count(EE)"/>
      </xsl:if>
    </xsl:for-each>
  </xsl:variable>

  <xsl:variable name="vNodes" select="(//*)[not(position() > $vMax)]"/>

  <xsl:variable name="vEmpty" select="'&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;'"/>

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

  <xsl:template match="CC">
    <xsl:copy>
      <xsl:apply-templates/>
      <xsl:apply-templates select=
          "$vNodes[not(position() > $vMax - count(current()/EE))]" mode="picture">
        <xsl:with-param name="pStart" select="count(EE)"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="CC/EE/EE1">
    <xsl:element name="EE{count(../preceding-sibling::EE)+1}">
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>

  <xsl:template match="*" mode="picture">
    <xsl:param name="pStart" select="0"/>
    <EE>
      <xsl:element 
        name="EE{$pStart + position()}"><xsl:value-of select="$vEmpty"/></xsl:element>
    </EE>
  </xsl:template>
</xsl:stylesheet>

在提供的XML文档上应用此转换时

<Item>
   <Description>
      <BB>Main1</BB>
      <CC>
         <DD>Content1</DD>
         <EE>
            <EE1>Answer1</EE1>
         </EE>
      </CC>
   </Description>
   <Description>
      <BB>Main2</BB>
      <CC>
         <DD>Content2</DD>
         <EE>
            <EE1>Answer2.1</EE1>
         </EE>
         <EE>
            <EE1>Answer2.2</EE1>
         </EE>
         <EE>
            <EE1>Answer2.3</EE1>
         </EE>
      </CC>
   </Description>
   <Description>
      <BB>Main3</BB>
      <CC>
         <DD>Content3</DD>
         <EE>
            <EE1>Answer3</EE1>
         </EE>
      </CC>
   </Description>
</Item>

产生了确切需要的正确结果

<Item>
   <Description>
      <BB>Main1</BB>
      <CC>
         <DD>Content1</DD>
         <EE>
            <EE1>Answer1</EE1>
         </EE>
         <EE>
            <EE2>       </EE2>
         </EE>
         <EE>
            <EE3>       </EE3>
         </EE>
      </CC>
   </Description>
   <Description>
      <BB>Main2</BB>
      <CC>
         <DD>Content2</DD>
         <EE>
            <EE1>Answer2.1</EE1>
         </EE>
         <EE>
            <EE2>Answer2.2</EE2>
         </EE>
         <EE>
            <EE3>Answer2.3</EE3>
         </EE>
      </CC>
   </Description>
   <Description>
      <BB>Main3</BB>
      <CC>
         <DD>Content3</DD>
         <EE>
            <EE1>Answer3</EE1>
         </EE>
         <EE>
            <EE2>       </EE2>
         </EE>
         <EE>
            <EE3>       </EE3>
         </EE>
      </CC>
   </Description>
</Item>