【问题标题】:How to Turn a Child Node Into an Attribute of the Current Node如何将子节点变成当前节点的属性
【发布时间】:2011-02-22 18:25:42
【问题描述】:

我在这里发现了一个类似的问题:

How to read attribute of a parent node from a child node in XSLT

但不完全是我需要的。假设在这里使用相同的示例:

<A>
 <b attr1="xx">
   <c>
    Turn this into an Attribute  
   </c>
 </b>
</A>

我希望在 xslt 之后生成的 xml 看起来像:

 <A>
  <b attr1="xx" cAttr="Turn this into an Attribute">
  </b>
 </A>

使用我目前的知识,我只能设法摆脱节点或将其名称更改为所需的名称“cAttr”,但我真的不知道如何将整个节点变成父节点的属性, 只知道如何引用父节点的属性字段在这里对我没有多大帮助。

我当前的代码如下所示:

<xsl:template match="c">
 <xsl:element name="cAttr">
    <xsl:apply-templates select="@*|node()"/>
  </xsl:element>
</xsl:template>

提前致谢。

【问题讨论】:

    标签: xml xslt


    【解决方案1】:
    <!-- match b node -->
    <xsl:template match="b">
      <!-- apply templates on all attributes and nodes. see two templates below -->
      <xsl:apply-templates select="@*|node()"/>
    </xsl:template>
    
    <!-- copy all existing attrs -->
    <xsl:template match="b/@*">
      <xsl:copy-of select="."/>
    </xsl:template>
    
    <!-- populate attributes from nodes -->
    <xsl:template match="b/node()">
      <xsl:attribute name="{name()}Attr"> <!-- attribute name -->
        <xsl:value-of select="text()"/> <!-- attribute value -->
      </xsl:attribute>
      <!-- match all attributes on child node -->
      <xsl:apply-templates select="@*">
        <xsl:with-param name="prefix" select="name()"/> <!-- pass node name to template -->
      </xsl:apply-templates>
    </xsl:template>
    
    <xsl:template match="b/node()/@*">
      <xsl:param name="prefix"/>
      <!-- creates attribute prefixed with child node name -->
      <xsl:attribute name="{$prefix}-{name()}">
        <xsl:value-of select="."/>
      </xsl:attribute>
    </xsl:template>
    

    【讨论】:

    • b/node() 不会也尝试将子元素的属性转换为“b”的属性吗?只是想在这里学习。
    【解决方案2】:

    除了@Flack 正确的推送方式,而且只是为了好玩,还有两种拉取方式:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:strip-space elements="*"/>
        <xsl:template match="node()|@*" name="identity">
            <xsl:copy>
                <xsl:apply-templates select="node()|@*"/>
            </xsl:copy>
        </xsl:template>
        <xsl:template match="b/*[1][self::c]" name="attribute" priority="1">
            <xsl:attribute name="cAttr">
                <xsl:value-of select="../c"/>
            </xsl:attribute>
        </xsl:template>
        <xsl:template match="b[c]/*[1]">
            <xsl:call-template name="attribute"/>
            <xsl:call-template name="identity"/>
        </xsl:template>
        <xsl:template match="b/c"/>
    </xsl:stylesheet>
    

    注意:只有模式匹配的规则会覆盖身份规则。

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:strip-space elements="*"/>
        <xsl:template match="node()|@*" name="identity">
            <xsl:copy>
                <xsl:apply-templates select="node()|@*"/>
            </xsl:copy>
        </xsl:template>
        <xsl:template match="b[c]/*[1]" priority="1">
            <xsl:attribute name="cAttr">
                <xsl:value-of select="../c"/>
            </xsl:attribute>
            <xsl:if test="not(self::c)">
                <xsl:call-template name="identity"/>
            </xsl:if>
        </xsl:template>
        <xsl:template match="b/c"/>
    </xsl:stylesheet>
    

    注意:一条规则,但有一些xsl:if

    两个输出:

    <A>
        <b attr1="xx" cAttr="Turn this into an Attribute"></b>
    </A>
    

    编辑:糟糕!我错过了剥离规则。

    【讨论】:

      【解决方案3】:

      不如 Gleb 的版本好,但如果我已经浪费了时间,为什么不发布它= ;)

      <!-- Identity template -->
      <xsl:template match="@*|node()">
          <xsl:copy>
              <xsl:apply-templates select="@*|node()"/>
          </xsl:copy>
      </xsl:template>
      
      <!-- assemble b element -->
      <xsl:template match="b">
          <b>
              <xsl:attribute name="attr1">
                  <xsl:value-of select="@attr1" />
              </xsl:attribute>
              <xsl:attribute name="cAttr">
                  <xsl:value-of select="c" />
              </xsl:attribute>
          </b>
      </xsl:template>
      
      <!-- ignore c element -->
      <xsl:template match="c" />
      

      【讨论】:

      • 是的,就像我说的那样,它不是很好。它仅适用于这种特定情况。谈到 XSL,我还是一名大一新生。 :|
      【解决方案4】:

      我更喜欢更简洁(尽管可能不太通用)的设计:

      <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
          <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
          <xsl:template match="node() | @*">
              <xsl:copy>
                  <xsl:apply-templates select="node() | @*"/>
              </xsl:copy>
          </xsl:template>
          <xsl:template match="b">
              <xsl:copy>
                  <xsl:copy-of select="@*"/>
                  <xsl:attribute name="cAttr">
                      <xsl:value-of select="normalize-space(c)"/>
                  </xsl:attribute>
                  <xsl:apply-templates select="*[not(self::c)]"/>
              </xsl:copy>
          </xsl:template>
      </xsl:stylesheet>
      

      像这样应用于 XML:

      <A>
          <b attr1="xx">
              <d>SomeNode</d>
              <c>
                  Turn this into an Attribute
              </c>
              <f>SomeMoreNode</f>
          </b>
      </A>
      

      结果将是:

      <A>
          <b attr1="xx" cAttr="Turn this into an Attribute">
              <d>SomeNode</d>
              <f>SomeMoreNode</f>
          </b>
      </A>
      

      【讨论】:

      • +1 这是一个更好且语义更正确的答案,此外我会将模板应用于c,以防万一没有人。或者在b 的模式中使用过滤器,例如b[c]
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-17
      • 1970-01-01
      • 1970-01-01
      • 2012-02-14
      相关资源
      最近更新 更多