Concatenate parent attributes recursively

此生再无相见时 提交于 2019-12-13 18:41:10

问题


Given the following XML:

<package>
    <node name="a">
        <node name="b"/>
        <node name="c"/>
        <node name="d">
            <node name="e"/>
            <node name="f"/>
            <node name="g">
                <node name="h"/>
            </node>
        </node>    
    </node>
</package>

I basically want to flatten the tree while concatenating the name attributes of each parent node element until the last node element:

<package>
    <node name="a-b"/>
    <node name="a-c"/>
    <node name="a-d-e"/>
    <node name="a-d-f"/>
    <node name="a-d-g-h"/>
</package>

What I got working so far is is properly generating a flat list of all node elements using a template and xsl:copy-of:

<xsl:template match="//node">
    <xsl:copy-of select="current()"/>
</xsl:template>

This gives me:

<package>
    <node name="b"/>
    <node name="c"/>
    <node name="e"/>
    <node name="f"/>
    <node name="h"/>
</package>

But I'm not sure how to properly continue from here. My intention was to extend the template and using xsl:attribute and xsl:for-each to concatenate and modify the attribute:

    <xsl:template match="node/@name">
        <xsl:attribute name="name">
            <xsl:for-each select="ancestor::node">
                <xsl:if test="position() > 1">.</xsl:if>
                <xsl:value-of select="@name"/>
            </xsl:for-each>
        </xsl:attribute>
    </xsl:template>

However, this only prints the node's data (if any). What am I missing here?

I have XSLT 2.0 available and I got my inspiration from this SO question.


回答1:


I basically want to flatten the tree while concatenating the name attributes of each parent node element until the last node element:

Here is a complete and working XSLT 2.0 solution:

<xsl:stylesheet version="2.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="node[*]"><xsl:apply-templates/></xsl:template>

  <xsl:template match="node[not(*)]/@name">
    <xsl:attribute name="name" select="string-join(../ancestor-or-self::node/@name, '-')"/>
  </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document:

<package>
    <node name="a">
        <node name="b"/>
        <node name="c"/>
        <node name="d">
            <node name="e"/>
            <node name="f"/>
            <node name="g">
                <node name="h"/>
            </node>
        </node>
    </node>
</package>

the wanted, correct result is produced:

<package>
   <node name="a-b"/>
   <node name="a-c"/>
   <node name="a-d-e"/>
   <node name="a-d-f"/>
   <node name="a-d-g-h"/>
</package>

II. XSLT 1.0 solution:

<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="node[*]"><xsl:apply-templates/></xsl:template>

  <xsl:template match="node[not(*)]/@name">
    <xsl:attribute name="name"><xsl:apply-templates select="." mode="gen"/></xsl:attribute>
  </xsl:template>

  <xsl:template match="node/@name" mode="gen">
    <xsl:apply-templates select="../parent::node/@name" mode="gen"/>
    <xsl:if test="../parent::node">-</xsl:if>
    <xsl:value-of select="."/>
  </xsl:template>
</xsl:stylesheet>

when this transformation is applied on the same XML document (above), the same correct result is produced:

<package>
   <node name="a-b"/>
   <node name="a-c"/>
   <node name="a-d-e"/>
   <node name="a-d-f"/>
   <node name="a-d-g-h"/>
</package>



回答2:


Use string-join:

<xsl:template match="node">
  <node name="{string-join(ancestor-or-self::node/@name, '-')}"/>
</xsl:template>


来源:https://stackoverflow.com/questions/57328070/concatenate-parent-attributes-recursively

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!