XSL基于子项向父级添加属性

时间:2012-02-28 20:38:03

标签: xml xslt

我使用XML开始使用php进行项目,现在我需要应用转换,所以我第一次发现了XSL ......

我遇到了问题:如何创建XSL以进行以下转换: - 以“attrib-”开头的节点转换为父节点的属性

实施例

<a1>
  <b1>
    <attrib-c1>12</attrib-c1>
    <c2>23</c2>
  </b1>
</a1>

应该成为:

<a1>
  <b1 c1="12">
    <c2>23</c2>
  </b1>
</a1>

我已经开始这样的解决方案了:

<xsl:stylesheet>
  <xsl:output method="xml"/>
  <xsl:template match="@*|*|text()">
    <xsl:copy>
      <xsl:apply-templates select="@*|*|text()"/>
    </xsl:copy>
  </xsl:template>
...
</xsl:stylesheet>

我需要一些帮助才能解决这个问题。提前谢谢......

3 个答案:

答案 0 :(得分:3)

XML输入(修改为略微增加复杂性。)

<a1>
  <b1 existing="attr">
    <attrib-c1>12</attrib-c1>
    <c2>23</c2>
    <attrib-dh>DevNull</attrib-dh>
  </b1>
</a1>

XSLT 1.0

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

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

  <xsl:template match="*">
    <xsl:copy>
      <xsl:apply-templates select="*[starts-with(name(),'attrib')]" mode="attr"/>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*[starts-with(name(),'attrib')]"/>

  <xsl:template match="*" mode="attr">
    <xsl:attribute name="{substring-after(name(),'-')}">
      <xsl:value-of select="."/>
    </xsl:attribute>
  </xsl:template>  

</xsl:stylesheet>

XML输出

<a1>
   <b1 c1="12" dh="DevNull" existing="attr">
      <c2>23</c2>
   </b1>
</a1>

答案 1 :(得分:1)

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0">

    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

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

    <!-- match elements with children like attrib- and copy/pass -->
    <xsl:template match="*[*[starts-with(name(.),'attrib')]]">
        <xsl:copy>
         <xsl:apply-templates select="*[starts-with(name(.),'attrib')]"/>
         <xsl:apply-templates select="@*|*[not(starts-with(name(.),'attrib'))]"/>
        </xsl:copy>
    </xsl:template>

    <!-- match elements like attrib- and output them as attribute -->
    <xsl:template match="*[starts-with(name(.),'attrib')]">
        <xsl:attribute name="{substring-after(name(.),'attrib-')}">
            <xsl:value-of select="."/>
        </xsl:attribute>
    </xsl:template>

</xsl:stylesheet>

答案 2 :(得分:1)

这几乎与DevNull的解决方案相同,但是如果现有属性与子元素定义的新属性之间存在冲突,后者将取代前者:< / p>

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

 <xsl:template match="*">
  <xsl:copy>
   <xsl:apply-templates select="@*"/>
   <xsl:apply-templates mode="attr" select="*[starts-with(name(), 'attrib-')]"/>
   <xsl:apply-templates/>
  </xsl:copy>
 </xsl:template>

 <xsl:template mode="attr" match="*[starts-with(name(), 'attrib-')]">
  <xsl:attribute name="{substring-after(name(), 'attrib-')}">
    <xsl:value-of select="."/>
  </xsl:attribute>
 </xsl:template>

 <xsl:template match="*[starts-with(name(), 'attrib-')]"/>
</xsl:stylesheet>

将此转换应用于以下XML文档

<a1>
  <b1 existing="attr" x="Y">
    <attrib-new>12</attrib-new>
    <c2>23</c2>
    <attrib-new2>ABCD</attrib-new2>
    <attrib-x>Z</attrib-x>
  </b1>
</a1>

产生了想要的正确结果

<a1>
   <b1 existing="attr" x="Z" new="12" new2="ABCD">
      <c2>23</c2>
   </b1>
</a1>