【问题标题】:Add attribute based on Node name (incremental) in xsl在 xsl 中添加基于节点名称(增量)的属性
【发布时间】:2017-12-20 21:20:42
【问题描述】:

我想根据节点名称为每个具有子元素的节点添加一个 ID 属性,但如果已经存在,则增加引用。虽然我可以添加属性,但我不确定如何根据以前的事件增加它们。对此的任何帮助将不胜感激

初始xml

<xml>
    <individual>
        <name>
            <firstname>Me</firstname>
            <lastname>Last</lastname>
        </name>
        <addresses>
            <address>
                <street>1234 Main</street>
                <city>Anytown</city>
                <state>TX</state>
            </address>
            <address>
                <street>4321 Central Ave</street>
                <city>Bixby</city>
                <state>ND</state>
            </address>
        </addresses>
        <employeers>
            <employeer>
                <name>
                    <firstname>Employer1</firstname>
                    <lastname>EmployerLast</lastname>
                </name>
                <addresses>
                    <address>
                        <street>1234 Employer1</street>
                        <city>Smallville</city>
                        <state>CT</state>
                    </address>
                </addresses>
            </employeer>
            <employeer>
                <name>
                    <firstname>Employer2</firstname>
                    <lastname>EmployerLast2</lastname>
                </name>
                <addresses>
                    <address>
                        <street>1234 Employer2</street>
                        <city>Nashville</city>
                        <state>TN</state>
                    </address>
                </addresses>
            </employeer>
        </employeers>
    </individual>
</xml>

想要的结果

<xml>
    <individual ID="indivdual_1">
        <name ID="name_1">
            <firstname>Me</firstname>
            <lastname>Last</lastname>
        </name>
        <addresses ID="addresses_1">
            <address ID="address_1">
                <street>1234 Main</street>
                <city>Anytown</city>
                <state>TX</state>
            </address>
            <address ID="address_2">
                <street>4321 Central Ave</street>
                <city>Bixby</city>
                <state>ND</state>
            </address>
        </addresses>
        <employeers ID="employeers_1">
            <employeer ID="employeer_1">
                <name ID="name_2">
                    <firstname>Employer1</firstname>
                    <lastname>EmployerLast</lastname>
                </name>
                <addresses ID="addresses_2">
                    <address ID="address_3">
                        <street>1234 Employer1</street>
                        <city>Smallville</city>
                        <state>CT</state>
                    </address>
                </addresses>
            </employeer>
            <employeer ID="employeer_2">
                <name ID="name_3">
                    <firstname>Employer2</firstname>
                    <lastname>EmployerLast2</lastname>
                </name>
                <addresses ID="addresses_3">
                    <address ID="address_4">
                        <street>1234 Employer2</street>
                        <city>Nashville</city>
                        <state>TN</state>
                    </address>
                </addresses>
            </employeer>
        </employeers>
    </individual>
</xml>

我找到了以下代码来计算特定元素的出现次数,但不确定如何将计数应用于特定节点。

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="text"/>

  <xsl:variable name="newline">
<xsl:text>
</xsl:text>
  </xsl:variable>

  <xsl:key name="elements" match="*" use="name()"/>

  <xsl:template match="/">
    <xsl:value-of select="$newline"/>
    <xsl:text>Summary of Elements</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:value-of select="$newline"/>
    <xsl:for-each 
      select="//*[generate-id(.)=generate-id(key('elements',name())[1])]">
      <xsl:sort select="name()"/>
      <xsl:for-each select="key('elements', name())">
        <xsl:if test="position()=1">
          <xsl:text>Element </xsl:text>
          <xsl:value-of select="name()"/>
          <xsl:text> occurs </xsl:text>
          <xsl:value-of select="count(//*[name()=name(current())])"/>
          <xsl:text> times.</xsl:text>
          <xsl:value-of select="$newline"/>
        </xsl:if>
      </xsl:for-each>
    </xsl:for-each>
    <xsl:value-of select="$newline"/>
    <xsl:text>There are </xsl:text>
    <xsl:value-of select="count(//*)"/>
    <xsl:text> elements in all.</xsl:text>
  </xsl:template>

</xsl:stylesheet>

【问题讨论】:

    标签: xml xslt


    【解决方案1】:

    我认为这是xsl:number的工作:

    <xsl:stylesheet
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="1.0">
    
      <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:attribute name="ID"><xsl:value-of select="local-name()"/>_<xsl:number level="any"/></xsl:attribute>
              <xsl:apply-templates/>
          </xsl:copy>
      </xsl:template>
    
    </xsl:stylesheet>
    

    参见http://xsltfiddle.liberty-development.net/b4GWV1,它将您发布的输入转换为输出

    <xml>
        <individual ID="individual_1">
            <name ID="name_1">
                <firstname>Me</firstname>
                <lastname>Last</lastname>
            </name>
            <addresses ID="addresses_1">
                <address ID="address_1">
                    <street>1234 Main</street>
                    <city>Anytown</city>
                    <state>TX</state>
                </address>
                <address ID="address_2">
                    <street>4321 Central Ave</street>
                    <city>Bixby</city>
                    <state>ND</state>
                </address>
            </addresses>
            <employeers ID="employeers_1">
                <employeer ID="employeer_1">
                    <name ID="name_2">
                        <firstname>Employer1</firstname>
                        <lastname>EmployerLast</lastname>
                    </name>
                    <addresses ID="addresses_2">
                        <address ID="address_3">
                            <street>1234 Employer1</street>
                            <city>Smallville</city>
                            <state>CT</state>
                        </address>
                    </addresses>
                </employeer>
                <employeer ID="employeer_2">
                    <name ID="name_3">
                        <firstname>Employer2</firstname>
                        <lastname>EmployerLast2</lastname>
                    </name>
                    <addresses ID="addresses_3">
                        <address ID="address_4">
                            <street>1234 Employer2</street>
                            <city>Nashville</city>
                            <state>TN</state>
                        </address>
                    </addresses>
                </employeer>
            </employeers>
        </individual>
    </xml>
    

    【讨论】:

    • 这是一个比我建议的更好的解决方案。 +1
    • 哇...这很简单但很有效...我会拔头发想弄清楚...谢谢
    • 在循环遍历属性时是否可以使用 xsl:number 来获取父节点或节点的计数?我根据自己的想法更新了代码,但它似乎没有按预期工作。 xsltfiddle.liberty-development.net/bFukv89/1.
    • 考虑为一个新问题提出一个新问题,在帖子中显示和解释你想要达到的结果。
    • 同一个主题,但在父节点或属性级别
    【解决方案2】:

    实现此目的的一种方法是为每个元素创建具有全局计数的替换模板。
    这意味着给定集合的六个模板:name、individual、address、addresses、employeers、employeer。

    每个模板都与// 匹配,以获取变量idx 中的全局计数。然后他们用副本替换当前节点并添加新的ID 属性。 身份模板复制所有其他节点。

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
    
    <!-- identity template -->
    <xsl:template match="node()|@*">
      <xsl:copy>
        <xsl:apply-templates select="node()|@*" />
      </xsl:copy>
    </xsl:template>
    
    <!-- global templates for specific element 'name' -->
    <xsl:template match="//name">
      <xsl:variable name="idx" select="count(preceding::name) + 1" />
      <xsl:copy>
        <xsl:attribute name="ID"><xsl:value-of select="concat(local-name(),'_',$idx)" /></xsl:attribute>
        <xsl:apply-templates select="node()|@*" />
      </xsl:copy>
    </xsl:template>
    
    <!-- global templates for specific element 'address' -->
    <xsl:template match="//address">
      <xsl:variable name="idx" select="count(preceding::address) + 1" />
      <xsl:copy>
        <xsl:attribute name="ID"><xsl:value-of select="concat(local-name(),'_',$idx)" /></xsl:attribute>
        <xsl:apply-templates select="node()|@*" />
      </xsl:copy>
    </xsl:template>
    
    <!-- global templates for specific element 'addresses' -->
    <xsl:template match="//addresses">
      <xsl:variable name="idx" select="count(preceding::addresses) + 1" />
      <xsl:copy>
        <xsl:attribute name="ID"><xsl:value-of select="concat(local-name(),'_',$idx)" /></xsl:attribute>
        <xsl:apply-templates select="node()|@*" />
      </xsl:copy>
    </xsl:template>
    
    <!-- global templates for specific element 'individual' -->
    <xsl:template match="//individual">
      <xsl:variable name="idx" select="count(preceding::individual) + 1" />
      <xsl:copy>
        <xsl:attribute name="ID"><xsl:value-of select="concat(local-name(),'_',$idx)" /></xsl:attribute>
        <xsl:apply-templates select="node()|@*" />
      </xsl:copy>
    </xsl:template>
    
    <!-- global templates for specific element 'employeers' -->
    <xsl:template match="//employeers">
      <xsl:variable name="idx" select="count(preceding::employeers) + 1" />
      <xsl:copy>
        <xsl:attribute name="ID"><xsl:value-of select="concat(local-name(),'_',$idx)" /></xsl:attribute>
        <xsl:apply-templates select="node()|@*" />
      </xsl:copy>
    </xsl:template>
    
    <!-- global templates for specific element 'employeer' -->
    <xsl:template match="//employeer">
      <xsl:variable name="idx" select="count(preceding::employeer) + 1" />
      <xsl:copy>
        <xsl:attribute name="ID"><xsl:value-of select="concat(local-name(),'_',$idx)" /></xsl:attribute>
        <xsl:apply-templates select="node()|@*" />
      </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>
    

    这是一个 XSLT-1.0 解决方案,输出应该符合要求。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-20
      • 1970-01-01
      • 1970-01-01
      • 2018-06-04
      • 2020-11-05
      相关资源
      最近更新 更多