我有以下XSLT,它为填充的XML文件中的每个元素创建XPATH。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" indent="no"/>
<xsl:template match="*[not(*)]">
    <xsl:for-each select="ancestor-or-self::*">
        <xsl:value-of select="concat('/', name())"/>
        <xsl:if test="count(preceding-sibling::*[name() = name(current())]) != 0">
            <xsl:value-of select="concat('[', count(preceding-sibling::*[name() = name(current())]) + 1, ']')"/>
        </xsl:if>
    </xsl:for-each>
    <xsl:text>&#xA;</xsl:text>
    <xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="*">
    <xsl:apply-templates select="*"/>
</xsl:template>
</xsl:stylesheet>


我想对此进行扩展,以使“属性”级别产生一个唯一的行。目前,即使给定元素具有多个属性,也会为其生成一个XPATH语句。如果一个元素具有3个属性,则我希望每个生成3条XPATH行。任何想法表示赞赏! :)谢谢

更新

嗨,伊恩,

非常感谢您的帮助。

我需要一种增强功能,我觉得很棘手吗?

当元素具有xsi:type属性(即是另一种类型的扩展)时,我需要在XPATH的元素名称中考虑它而不是将其视为属性本身(因为它是特殊的/保留XSD属性)

例如对于

<a>
   <b xsi:type="c" attribute1="at1"/>
</a>


我需要:

/a/b[xsi:type="c"]/@attribute1


而不是

/a/b/@type


目前正在生产什么?这可能吗?

谢谢!

更新

很好,谢谢!最后一个要求是请。 :)您可以对其进行调整以从XML添加元素或属性VALUE,并以逗号分隔XPATH部分与XPATH部分吗..... [XPATH],[VALUE]是

最佳答案

我将把生成代码的路径拉到另一个模板中,然后从模板中调用该元素和属性:

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

  <xsl:template mode="path" match="*">
    <xsl:for-each select="ancestor-or-self::*">
      <xsl:value-of select="concat('/', name())" />
      <xsl:if test="count(preceding-sibling::*[name() = name(current())]) != 0">
        <xsl:value-of select="concat('[',
          count(preceding-sibling::*[name() = name(current())]) + 1, ']')" />
      </xsl:if>
    </xsl:for-each>
  </xsl:template>

  <xsl:template match="*">
    <xsl:if test="not(*)">
      <!-- this element has no children, print its path -->
      <xsl:apply-templates mode="path" select="." />
      <xsl:text>&#xa;</xsl:text>
    </xsl:if>
    <xsl:apply-templates select="@*|*" />
  </xsl:template>

  <xsl:template match="@*">
    <!-- for an attribute, print the path to its containing element ... -->
    <xsl:apply-templates mode="path" select=".." />
    <!-- ... followed by "/@attributename" -->
    <xsl:value-of select="concat('/@', name(), '&#xa;')" />
  </xsl:template>
</xsl:stylesheet>


XPath数据模型的一个方便之处在于,虽然属性节点不被视为其宿主元素节点的子级,但该元素被视为其属性节点的父级。



更新:要处理xsi:type要求,您应该只需要将该逻辑添加到当前的同级计数代码中,就可以区别对待键入的元素。要添加这些值,您需要在适当的位置添加适当的value-of

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <xsl:output method="text" indent="no" />

  <xsl:template mode="path" match="*">
    <xsl:for-each select="ancestor-or-self::*">
      <xsl:value-of select="concat('/', name())" />
      <!-- for typed elements, include the type in the path -->
      <xsl:if test="@xsi:type">
        <xsl:text>[@xsi:type = '</xsl:text>
        <xsl:value-of select="@xsi:type" />
        <xsl:text>']</xsl:text>
      </xsl:if>
      <xsl:if test="count(preceding-sibling::*[name() = name(current()) and
            @xsi:type = current()/@xsi:type]) != 0">
        <xsl:value-of select="concat('[',
          count(preceding-sibling::*[name() = name(current()) and
            @xsi:type = current()/@xsi:type]) + 1, ']')" />
      </xsl:if>
    </xsl:for-each>
  </xsl:template>

  <xsl:template match="*">
    <xsl:if test="not(*)">
      <!-- this element has no children, print its path -->
      <xsl:apply-templates mode="path" select="." />
      <xsl:text>,</xsl:text>
      <xsl:value-of select="."/>
      <xsl:text>&#xa;</xsl:text>
    </xsl:if>
    <xsl:apply-templates select="@*|*" />
  </xsl:template>

  <xsl:template match="@*">
    <!-- for an attribute, print the path to its containing element ... -->
    <xsl:apply-templates mode="path" select=".." />
    <!-- ... followed by "/@attributename" -->
    <xsl:value-of select="concat('/@', name(), ',', ., '&#xa;')" />
  </xsl:template>
</xsl:stylesheet>


由于空节点集的字符串值是空字符串,因此对没有@xsi:type = current()/@xsi:type的元素进行xsi:type是安全的,并且将产生正确的结果。

您可能还想添加

<xsl:template match="@xsi:type" />


如果您不想生成类型属性的路径。

这里值得注意的是类型逻辑和计数是正交的-给定

<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <a xsi:type="xs:string">aaa</a>
  <a xsi:type="xs:integer">1</a>
  <a xsi:type="xs:string">bbb</a>
  <a xsi:type="xs:integer">2</a>
</root>


你会得到

/root/a[@xsi:type = 'xs:string'],aaa
/root/a[@xsi:type = 'xs:integer'],1
/root/a[@xsi:type = 'xs:string'][2],bbb
/root/a[@xsi:type = 'xs:integer'][2],2


带有每种类型的计数(正确的是,XPath将在假设正确的名称空间绑定的情况下选择正确的东西)。

10-07 19:22
查看更多