2016-07-27 18 views
0

Um den XPath für jeden Knoten in einer XML-Datei zu generieren und diesen Pfad als Attribut zu jedem Knoten hinzuzufügen, habe ich eine Hilfe gefunden here. Die xslt-Datei sollte so aussehen:Generiere XPath von Knoten mit xslt 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> 

Jetzt interessiert mich eine kompaktere Art und Weise mit xslt 2.0. Zum Beispiel habe ich in der folgenden xslt Datei zwei Funktionen createXPath und getXpath. Der erste gibt einen Pfad mit Knotennamen zurück und der zweite gibt die entsprechende Nummer zurück. Ist es möglich, diese auf intelligente Weise zu kombinieren?

Antwort

1

Die Kombination der beiden Funktionen ist ziemlich trivial wäre generieren - zum Beispiel, könnten Sie tun, :

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

Allerdings ist diese Methode ziemlich ineffizient, da sie den Baum wiederholt durchlaufen muss ly. Betrachten Sie stattdessen:

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

, die das rekursive Verarbeitungsmodell von XSLT nutzt.

0

Ein paar Punkte.

(a) Es gibt keinen "XPath eines Knotens". Einige Leute, wenn sie einen solchen Begriff verwenden, werden einen Pfad wie a/b/c bedeuten, andere werden a[1]/b[5]/c[6] bedeuten, und andere werden einen Pfad bedeuten, der vollständig namespacequalifiziert ist, indem Prädikate auf jeder Ebene verwendet werden, die namespace-uri() testet.

(b) XPath 3.0 bietet eine Funktion path(), die einen XPath-Ausdruck dieser Art zurückgibt; Es verwendet die EQName-Syntax Q{uri}local, um sicherzustellen, dass Elementnamen kontextfrei sind.

(c) Mein Ansatz die Art von Weg zu bekommen Sie

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

und dann

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

Ich glaube nicht, dass Sie diese getestet haben. –

+0

Ich teste sehr selten Code-Beispiele. Ich denke, es ist wichtig, dass der Leser den Code versteht und nicht nur wortwörtlich verwendet. –