XSLT:将没有子节点的子节点转换为属性?

时间:2014-01-24 15:40:43

标签: xml xslt

我需要生成一个XML文档,以便与第三方供应商集成。他们的范例是任何字符串元素都被设置为属性,而任何复杂对象都是具有相同规则的单独节点。

我正在尝试使用XSLT将此对象的序列化表示形式转换为基于其.dtd的文档格式。不幸的是,我无法使用[XmlAttribute]装饰这些特定元素,因为它们的值可能为null(我在发送请求之前使用XSLT删除这些节点)。

基本上,我试图在XSLT中弄清楚如何执行以下操作:“对于我的元素的每个子节点,如果该子节点没有子节点,则将该元素转换为元素上的属性。” /强>

我正在使用以下代码片段,我发现它似乎可以满足我的需求:

<!-- Match elements that are parents -->
<xsl:template match="*[*]">
  <xsl:choose>
    <!-- Only convert children if this element has no attributes -->
    <!-- of its own -->
    <xsl:when test="not(@*)">
      <xsl:copy>
        <!-- Convert children to attributes if the child has -->
        <!-- no children or attributes and has a unique name -->
        <!-- amoung its siblings -->
        <xsl:for-each select="*">
          <xsl:choose>
            <xsl:when test="not(*) and not(@*) and
                            not(preceding-sibling::*[name( ) =
                                                     name(current( ))]) 
                            and 
                            not(following-sibling::*[name( ) = 
                                                     name(current( ))])">
              <xsl:attribute name="{local-name(.)}">
                <xsl:value-of select="."/>
              </xsl:attribute>  
            </xsl:when>
            <xsl:otherwise>
              <xsl:apply-templates select="."/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:for-each>
      </xsl:copy>
    </xsl:when>
    <xsl:otherwise>
      <xsl:copy>
        <xsl:apply-templates/>
      </xsl:copy>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

然而,这个错误与:

  

异常:: System.Xml.Xsl.XslTransformException:属性和   命名空间节点不能在文本后添加到父元素,   已添加comment,pi或子元素节点。

我的XSLT技能有点弱。任何帮助将不胜感激!

有关详情,请说文档如下:

<Root>
    <type>Foo</type>
    <includeHTML>Yes</includeHTML>
    <SubRoot>
        <SubSubRoot>
            <ID>2.4</ID>
        </SubSubRoot>
    </SubRoot>
</Root>

我希望结果看起来像这样:

<Root type="foo" includeHTML="Yes">
    <SubRoot>
        <SubSubRoot ID="2.4" />
    </SubRoot>
</Root>

编辑编辑:我只使用.NET 4.5.1,XSLT 1.0。卫生署!

1 个答案:

答案 0 :(得分:0)

我不完全确定你在问什么,但我会试一试。

此样式表假定仅包含文本节点的元素被包含为父元素的属性 - 即使文本节点在某种意义上是元素的子元素。

<?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" indent="yes"/>

   <xsl:template match="/*|*[*]">
      <xsl:copy>
         <xsl:apply-templates select="@*"/>
         <xsl:choose>
            <xsl:when test="*[not(./*) and not(./@*)]">
               <xsl:for-each select="*[not(./*) and not(./@*)]">
                  <xsl:attribute name="{current()/local-name()}">
                    <xsl:value-of select="."/>
                  </xsl:attribute>
               </xsl:for-each>
            </xsl:when>
            <xsl:otherwise/>
         </xsl:choose>                
         <xsl:apply-templates select="*[*]"/>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="*[not(./*) and not(./@*)]"/>

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

</xsl:stylesheet>

应用于样本输入:

<?xml version="1.0" encoding="utf-8"?>

<root>
   <car nr="1">
      <color>blue</color>
      <speed>210</speed>
   </car>
   <car nr="2">
      <color>red</color>
      <speed>100</speed>
   </car>
</root>

您会得到以下结果:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <car nr="1" color="blue" speed="210"/>
   <car nr="2" color="red" speed="100"/>
</root>

编辑:应用于您的更新输入,我得到:

<?xml version="1.0" encoding="UTF-8"?>
<Root type="Foo" includeHTML="Yes">
   <SubRoot>
      <SubSubRoot ID="2.4"/>
   </SubRoot>
</Root>