2016-07-27 9 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という2つの関数を持っています。最初のノードはノード名のあるパスを返し、2番目のノードは対応する番号を返します。それらをスマートな方法で組み合わせることは可能ですか?

<?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> 

しかし、この方法は、ツリーを横断しなければならないため、非常に非効率的ですまあ。代わりに、XSLTの再帰処理モデルを利用する

<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> 

を考慮してください。

0

2点。

(a)「ノードのXPath」というものはありません。そのような用語を使用する人は、a/b/cのようなパスを意味するものもあれば、a[1]/b[5]/c[6]を意味するものもあれば、namespace-uri()をテストする各レベルの述語を使って完全に名前空間修飾されたパスを意味するものもあります。

(b)XPath 3.0は、この種のXPath式を返す関数パス()を提供します。 EQName構文Q{uri}localを使用して、要素名がコンテキストフリーであることを確認します。

(c)は、あなたが生成しているパスの種類は2つの機能を組み合わせる

<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

私はごくまれにテストコードサンプルをテストします。読者はコードをそのまま使うのではなく、そのコードを理解して、間違ったエラーを残すことがそのコードを確実にするのに役立つことが重要だと思います。 –

関連する問題