2016-07-27 57 views
0

要为xml文件中的每个节点生成xpath并将此路径作为属性添加到每个节点,我发现一些帮助here。 xslt文件应该如下所示:使用xslt生成xpath节点2

<?xml version="1.0" encoding="UTF-8" ?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes" encoding="UTF-8"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:template match="@*|node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="*"> 
    <xsl:copy> 
     <xsl:attribute name="xpath"> 
     <xsl:for-each select="ancestor-or-self::*"> 
      <xsl:value-of select="concat('/',local-name())"/> 
      <!--Predicate is only output when needed.--> 
      <xsl:if 
      test="(preceding-sibling::*|following-sibling::*)[local-name()=local-name(current())]"> 
      <xsl:value-of 
       select="concat('[',count(preceding-sibling::*[local-name()=local-name(current())])+1,']')" 
      /> 
      </xsl:if> 
     </xsl:for-each> 
     </xsl:attribute> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="text()"/> 

</xsl:stylesheet> 

现在我对使用xslt 2.0更紧凑的方式感兴趣。例如在下面的xslt文件中,我有两个函数createXPath和getXpath。第一个返回一个带有节点名称的路径,第二个返回相应的数字。是否可以巧妙地将这些组合起来?

<?xml version="1.0" encoding="UTF-8" ?> 
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:func="http://www.functx.com"> 
    <xsl:output method="xml" encoding="utf-8"/> 

<xsl:template match="@*|node()"> 
    <xsl:copy> 
     <xsl:attribute name="xpath"> 
      <xsl:value-of select="func:getXpath(.)"/> 
     </xsl:attribute> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
</xsl:template> 

    <xsl:function name="func:createXPath" > 
    <xsl:param name="pNode" as="node()"/> 
    <xsl:value-of select="$pNode/ancestor-or-self::*/local-name()" separator="/"/> 
    </xsl:function> 

    <xsl:function name="func:getXpath"> 
    <xsl:param name="pNode" as="node()"/> 
    <xsl:value-of select="$pNode/ancestor-or-self::*/(count(preceding-sibling::*) + 1)" separator="/" /> 
</xsl:function> 

</xsl:stylesheet> 

回答

1

结合使用这两种功能是相当微不足道的 - 例如,你可以做:

<xsl:function name="func:path" > 
    <xsl:param name="target" as="element()"/> 
    <xsl:value-of select="for $step in $target/ancestor-or-self::* return concat(name($step), '[', count($step/preceding-sibling::*[name() = name($step)]) + 1, ']')" separator="/"/> 
</xsl:function> 

然而,这种方法效率很低,因为它必须遍历重复的树LY。请考虑:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:template match="*"> 
    <xsl:param name="path"/> 
    <xsl:variable name="my-path"> 
     <xsl:value-of select="$path"/> 
     <xsl:text>/</xsl:text> 
     <xsl:value-of select="name()"/> 
     <xsl:text>[</xsl:text> 
     <xsl:value-of select="count(preceding-sibling::*[name() = name(current())]) + 1"/> 
     <xsl:text>]</xsl:text> 
    </xsl:variable> 
    <xsl:copy> 
     <xsl:attribute name="xpath"> 
      <xsl:value-of select="$my-path" />  
     </xsl:attribute> 
     <xsl:copy-of select="@*"/> 
     <xsl:apply-templates> 
      <xsl:with-param name="path" select="$my-path"/> 
     </xsl:apply-templates> 
    </xsl:copy> 
</xsl:template> 

</xsl:stylesheet> 

它利用了XSLT的递归处理模型。

0

几点。

(a)没有“节点的XPath”这样的事情。有些人在使用这样一个术语时,意味着像a/b/c这样的路径,其他人将意味着a[1]/b[5]/c[6],而其他人则意味着通过在测试namespace-uri()的每个级别使用谓词来完全命名空间限定的路径。 (b)XPath 3.0提供了一个函数path(),它返回这种类型的XPath表达式;它使用EQName语法Q{uri}local确保元素名称无上下文。

(三)我的办法来获取路径要生成那种会

<xsl:function name="f:path" as="xs:string"> 
    <xsl:param name="e" as="element(*)"/> 
    <xsl:value-of select="ancestor-or-self::*/concat(
    '/', 
    name($e), 
    concat('[',f:index($e),']')[. ne '[1]'] 
)" separator=""/> 
</xsl:function> 

<xsl:function name="f:index" as="xs:integer"> 
    <xsl:param name="e" as="element(*)"/> 
    <xsl:sequence select="count(preceding-sibling::*[name()=name($e)])+1"/> 
</xsl:function> 

然后

<xsl:copy> 
    <xsl:attribute name="path" select="f:path(.)"/> 
    .... 
</xsl:copy> 
+0

我不认为你已经测试过这些。 –

+0

我很少测试代码示例。我认为读者应该理解代码而不是逐字逐句地使用它是很重要的,而留下奇怪的错误有助于确保这一点。 –