2017-01-16 1 views
0

Ich transformiere XML mit XSLT 2.0. Es ist wichtig, dass alle Textknoten aus der XML-Eingabe in der resultierenden XML-Datei enthalten sind, und zwar in der Reihenfolge, in der sie in der Eingabe aufgetreten sind. Für die Elementknoten möchte ich in den meisten Fällen nur den Namen des Tags ändern oder eine Hierarchie hinzufügen, um bestimmte Knoten in einen neuen Knoten einzufügen.XSLT 2: Wie wird der gesamte Inhalt zwischen dem ersten und letzten Auftreten eines XML-Tags eingefügt?

Für diese Frage möchte ich wissen, wie ich den gesamten Inhalt von (einschließlich) dem ersten Kindvorkommen eines bestimmten Tags bis (einschließlich) dem letzten Kindvorkommen desselben Tags als eine "Einheit" behandeln kann, einschließlich Text und andere Tags dazwischen. Gleichzeitig möchte ich auch alle Kinder, die dieser Selektion vorausgehen, als eine eigene "Einheit" behandeln, und alle Kinder, die dieser Selektion folgen, als eine weitere separate "Einheit".

Ich habe ein Dummy-Beispiel von dem, was ich will, aufgenommen. Angenommen, der "aktuelle Knoten" ist <c>, z. wenn wir in einer <xsl:template match="//c"> sind. Ich möchte alles (unter <c>) vom ersten <e> Knoten bis zum letzten <e> Knoten (einschließlich), einschließlich der <f> Knoten, in einem Knoten <es>. Ich würde außerdem (immer noch nur im Kontext <c>) gerne alles vorher so lassen wie es ist, aber alles danach in einen Knoten einbinden <after-es>. Ich möchte dies ohne irgendwelche Nebenwirkungen außerhalb von <c>, wie das Verschieben von Inhalten in oder aus dem <c> Knoten.

XML-Input-:

<a> 
    alfred 
    <b>bob</b> 
    charlie 
    <c> 
    dover 
    <d>elon</d> 
    fabio 
    <e>grant</e> 
    hugh 
    <f>illinois</f> 
    jacob 
    <e>kathy</e> 
    lombard 
    <e> 
     moby 
     <g>narwhal</g> 
     obi-wan 
    </e> 
    pontiac 
    <h>quantas</h> 
    rhino 
    </c> 
    xenu 
    <z>yoga</z> 
    zombie 
</a> 

Erwartete XML-Ausgabe:

<a> 
    alfred 
    <b>bob</b> 
    charlie 
    <c> 
    dover 
    <d>elon</d> 
    fabio 
    <es> 
     <e>grant</e> 
     hugh 
     <f>illinois</f> 
     jacob 
     <e>kathy</e> 
     lombard 
     <e> 
     moby 
     <g>narwhal</g> 
     obi-wan 
     </e> 
    </es> 
    <after-es> 
     pontiac 
     <h>quantas</h> 
     rhino 
    </after-es> 
    </c> 
    xenu 
    <z>yoga</z> 
    zombie 
</a> 

Wie dies geschehen kann? Vorzugsweise mit XSLT 2.0. Je besser die Lösung, desto besser.

+0

Was passiert, wenn es nur ein einziges 'e' Kind in einem bestimmten 'c' Elemente ist, welche Elemente haben Sie dann wickeln wollen? –

+0

@MartinHonnen Wenn die 'c' Knoten nur ein Kind hat und das Kind ist ein 'e', dann würde ich aussehen will wie' ... ... ... '. Ob der 'after-es'-Knoten enthalten ist, wenn er keinen Inhalt hat, ist keine große Sache, aber vorzugsweise nicht. –

+0

ich frage eg' foo baz ... foobar .. ', so ist es nur ein einziges' e' Kind, aber es gibt auch andere untergeordnete Knoten, auch einig folgenden 'e', Möchten Sie nur das 'e' Element oder auch die Knoten nach dem' e' Element umbrechen? –

Antwort

2

Hier ist eine Art und Weise man es aussehen könnte:

XSLT 2,0

<xsl:stylesheet version="2.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="*"/> 

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

<xsl:template match="c"> 
    <xsl:variable name="nodes-before" select="node()[. &lt;&lt; ../e[1]]"/> 
    <xsl:variable name="nodes-after" select="node()[. >> ../e[last()]]"/> 
    <xsl:copy> 
     <xsl:apply-templates select="$nodes-before"/> 
     <es> 
      <xsl:apply-templates select="node() except ($nodes-before|$nodes-after)"/> 
     </es> 
     <xsl:if test="$nodes-after"> 
      <after-es> 
       <xsl:apply-templates select="$nodes-after"/> 
      </after-es> 
     </xsl:if> 
    </xsl:copy> 
</xsl:template> 

</xsl:stylesheet> 

Beachten Sie, dass es eine zugrunde liegende Annahme ist hier, dass c mindestens ein e Kind hat.

+0

Schön, genau die Art von Lösung, auf die ich gehofft hatte! Viel besser als die Lösung, die ich mit einer schrecklichen Kombination von 'position()' und 'count()' kochte. –

0

Meine eigene Lösung zu lösen, begann, bevor ich die Antwort von @ michael.hor257k sah.

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="2.0"> 

    <xsl:output omit-xml-declaration="yes" /> 

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

    <xsl:template match="c"> 
    <xsl:variable name="first-e" select="count(e[  1]/preceding-sibling::node()) + 1"/> 
    <xsl:variable name="last-e" select="count(e[last()]/preceding-sibling::node()) + 1"/> 

    <xsl:copy> 
     <xsl:apply-templates select="e[1]/preceding-sibling::node()"/> 
     <es> 
     <xsl:apply-templates select="node()[$first-e &lt;= position() and position() &lt;= $last-e]"/> 
     </es> 
     <after-es> 
     <xsl:apply-templates select="e[last()]/following-sibling::node()"/> 
     </after-es> 
    </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 
Verwandte Themen