用于计算唯一后代元素的 XPath 表达式



我正在编写一个 XPath 表达式来计算唯一的子属性。使用以下 xPath 表达式,我可以获取所有不唯一的子属性:

//*[count(*)=0] 

我需要一个 XPath 表达式来返回所有唯一属性和唯一属性的数量

例如:XML文件

<details>
    <Employee>
        <EmpNo>10</EmpNo>
        <EmpName>TestName</EmpName>
        <Address>
           <Address1>market</Address1>
           <Address2>motel</Address2>
           <Street/>
        </Address>
    </Employee>
    <Employee>
        <EmpNo>20</EmpNo>
        <EmpName>TestName2</EmpName>
        <Address>
           <Address1>school</Address1>
           <Address2>playground</Address2>
           <Street>
                <StreetName>TestStreet2</StreetName>
                <StreetCode>200</StreetCode>
           </Street>
        </Address>
    </Employee>

预期产出:

  <!-- Unique element's count -->
  <data>6</data>
  <!-- Unique Element Names -->
  <data>EmpNo</data>
  <data>EmpName</data>
  <data>Address1</data>
  <data>Address2</data>
  <data>StreetName</data>
  <data>StreetCode</data>
  <!-- Unique Element values -->
  <!-- Data Set 1 -->
  <data>10</data>
  <data>TestName</data>
  <data>market</data>
  <data>motel</data>
  <data>null</data>
  <data>null</data>
  <!-- Data Set 2 -->
  <data>20</data>
  <data>TestName2</data>
  <data>school</data>
  <data>playground</data>
  <data>TestStreet2</data>
  <data>200</data>

谢谢。

此 XSLT 1.0 样式表

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output indent="yes" omit-xml-declaration="yes" />
  <!-- index data fields by their element name -->
  <xsl:key 
    name  = "kFields" 
    match = "Employee//*"
    use   = "name()" 
  />
  <!-- store a unique list of elements (Muenchian Grouping) -->    
  <xsl:variable name="fields" select="
    /details/Employee//*[
      generate-id()
      =
      generate-id(key('kFields', name())[1])
    ][
      not(
        key('kFields', name())/*
      )
    ]
  " />
  <!-- main output ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
  <xsl:template match="/details">
    <xsl:comment> unique element count </xsl:comment>
    <data>
      <xsl:value-of select="count($fields)" />
    </data>
    <xsl:call-template name="newline" />
    <xsl:comment> unique element names </xsl:comment>
    <xsl:for-each select="$fields">
      <data>
        <xsl:value-of select="name()" />
      </data>
      <xsl:call-template name="newline" />
    </xsl:for-each>
    <xsl:comment> unique element values </xsl:comment>
    <xsl:apply-templates select="Employee" />
  </xsl:template>
  <!-- Employee output ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
  <xsl:template match="Employee">
    <xsl:variable name="this" select="." />
    <xsl:comment> data set <xsl:value-of select="position()" /> </xsl:comment>
    <xsl:for-each select="$fields">
      <xsl:variable 
        name="val" 
        select="$this//*[not(*) and name() = name(current())]" 
      />
      <data>
        <xsl:choose>
          <xsl:when test="normalize-space($val) != ''">
            <xsl:value-of select="$val" />
          </xsl:when>
          <xsl:otherwise>
            <xsl:text>null</xsl:text>
          </xsl:otherwise>
        </xsl:choose>
      </data>
      <xsl:call-template name="newline" />
    </xsl:for-each>
  </xsl:template>
  <!-- Helpers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
  <xsl:template name="newline">
    <xsl:value-of select="'&#xA;'" />
  </xsl:template>
</xsl:stylesheet>

产生(换行符可能会以不同的方式为您复制(:

<!-- unique element count -->
<data>6</data>
<!-- unique element names -->
<data>EmpNo</data>
<data>EmpName</data>
<data>Address1</data>
<data>Address2</data>
<data>StreetName</data>
<data>StreetCode</data>
<!-- unique element values -->
<!-- data set 1 -->
<data>10</data>
<data>TestName</data>
<data>market</data>
<data>motel</data>
<data>null</data>
<data>null</data>
<!-- data set 2 -->
<data>20</data>
<data>TestName2</data>
<data>school</data>
<data>playground</data>
<data>TestStreet2</data>
<data>200</data>

笔记:

  • //*[count(*)=0]//*[not(*)]是平等的。后者更好。
  • 我使用<xsl:key>Muenchian分组来找出<Employee>后代中的唯一元素名称
  • 变量 $fields 中的 XPath 表达式执行两项操作:
    • 首先,它使用元素的Muenchian分组,使它们通过name()而独特。
    • 然后它检查其余元素。同名元素在输入(not( key('kFields', name())/* )(中的任何位置都不能有任何子元素。否则<data>Street</data>将显示在输出中。
  • 您的输出格式不明确。如果有些元素具有相同的名称但不同的嵌套位置,事情就会变得混乱。

最新更新