2017-07-06 7 views
0

ich auf XSLT arbeitete, die ein logisches Duplikate zu ignorieren hat mit (MySegment/*[not(.=preceding::*)]).XSLT: Ignorieren Duplikate Ähnliche Werte

Eingang:

<MySegment> 
<Field1>ABCD</Field1> 
<FIeld2>1</Field2> 
</MySegment> 
<MySegment> 
<Field1>ABCD123</Field1> 
<FIeld2>1</Field2> 
</MySegment> 

Hier haben wir zwei verschiedene Werte, aber da ABCD123 ABCD enthält auch , es wird als ein doppelter Eintrag behandelt. Kann jemand beraten.

Hier ist, wie mein XSLT wie folgt aussieht:

<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:template match="/RecordsInp"> 


      <xsl:for-each select="ParentSegment"> 


<xsl:for-each select="./MySegment/*[not(.=preceding::*)]"> 

        <A> 
         <Field1><xsl:value-of select ="name(.)"/></Field1> 
         <Field2><xsl:value-of select="."/></Field2> 
        </A> 

       </xsl:for-each> 

</xsl:for-each> 

    </xsl:template> 

</xsl:stylesheet> 

Meine Eingabe ist:

<RecordsInp> 
<ParentSegment> 
<MySegment> 
<Field1>ABC</Field1> 
<Field2>A1</Field2> 
</MySegment> 

    <MySegment> 
    <Field1>ABC</Field1> 
    <Field2>A1</Field2> 
    </MySegment> 
    <MySegment> 
    <Field1>ABCDEF</Field1> 
    <Field2>ABC</Field2> 
    </MySegment> 
    </ParentSegment> 
    </RecordsInp> 

Was ich erhalte ist:

<?xml version="1.0" encoding="UTF-8"?> 
    <A> 
     <Field1>Field1</Field1> 
     <Field2>ABC</Field2> 
    </A><A> 
     <Field1>Field2</Field1> 
     <Field2>A1</Field2> 
    </A><A> 
     <Field1>Field1</Field1> 
     <Field2>ABCDEF</Field2> 
    </A> 

Hinweis Ich bin nicht Field2 bekommen = ABC beim letzten Auftreten. Da Field2 ABC nie in früheren Vorkommnissen hatte, muss ich unter XML:

<?xml version="1.0" encoding="UTF-8"?> 
<A> 
    <Field1>Field1</Field1> 
    <Field2>ABC</Field2> 
</A><A> 
    <Field1>Field2</Field1> 
    <Field2>A1</Field2> 
</A><A> 
    <Field1>Field1</Field1> 
    <Field2>ABCDEF</Field2> 
</A> 
<A> 
    <Field1>Field2</Field1> 
    <Field2>ABC</Field2> 
</A> 
+2

* "Da ABCD123 auch ABCD enthält, wird es als Duplikat behandelt" * - Nein, nicht durch den XPath, den Sie anzeigen. – Tomalak

+0

Könnten Sie bitte beraten, wie dies zu korrigieren ist.Mein Ziel ist es, alle Felder dieses Segments zu durchlaufen und sie ohne Duplikate im Header zu füllen. – Tpi

+0

Wir können Ihnen nicht raten, wie Sie Ihren Code korrigieren können, ohne dass Sie genau erklären, was Ihr Code tun soll, und mindestens einen charakteristisches Beispiel, das das fehlerhafte Verhalten demonstriert. Zusammen mit der Beispieleingabe und der erwarteten und beobachteten Ausgabe nennen wir dies ein [mcve], und es ist das, was wir von Ihnen erwarten, wenn Sie nach Hilfe fragen, die Ihren Code repariert. –

Antwort

0

Basierend auf dem zweiten Eingangs Beispiel ist der Grund, warum Ihr Stylesheet nicht <Field2>ABC</Field2> ziehen die Art und Weise Sie ist erwarten, weil ABC als Wert in a existiert vorhergehende Field1.

Sie konnte testen auch den Namen gegen den Strom (current()) Namen in das Prädikat, aber vielleicht sollten Sie versuchen, mit einem xsl:key (Muenchian grouping) anstelle der preceding:: Achse ...

XML-Eingabe

<RecordsInp> 
    <ParentSegment> 
     <MySegment> 
      <Field1>ABC</Field1> 
      <Field2>A1</Field2> 
     </MySegment> 
     <MySegment> 
      <Field1>ABC</Field1> 
      <Field2>A1</Field2> 
     </MySegment> 
     <MySegment> 
      <Field1>ABCDEF</Field1> 
      <Field2>ABC</Field2> 
     </MySegment> 
    </ParentSegment> 
</RecordsInp> 

XSLT 1,0

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

    <xsl:key name="fields" match="MySegment/*" 
    use="concat(name(),'|',normalize-space())"/> 

    <xsl:template match="MySegment"> 
    <xsl:for-each 
     select="*[count(.|key('fields',concat(name(),'|',normalize-space()))[1])=1]"> 
     <A> 
     <Field1><xsl:value-of select="name()"/></Field1> 
     <Field2><xsl:value-of select="."/></Field2> 
     </A> 
    </xsl:for-each> 
    </xsl:template> 

</xsl:stylesheet> 

Ausgabe

<A> 
    <Field1>Field1</Field1> 
    <Field2>ABC</Field2> 
</A> 
<A> 
    <Field1>Field2</Field1> 
    <Field2>A1</Field2> 
</A> 
<A> 
    <Field1>Field1</Field1> 
    <Field2>ABCDEF</Field2> 
</A> 
<A> 
    <Field1>Field2</Field1> 
    <Field2>ABC</Field2> 
</A> 
+0

Der Trick, Meunchian Gruppierung auf ein Problem wie diese anzuwenden, ist natürlich, eindeutige Schlüsselwerte zu konstruieren. Wenn Sie einen Schlüssel durch Verketten mehrerer separater Werte bilden müssen, besteht immer die Gefahr, dass Sie von dem gewählten Begrenzer, der in den Daten erscheint, verwirrt werden. Natürlich wird das mit diesem Stylesheet und den Beispieldaten des OP nicht passieren, aber es ist wichtig, die Möglichkeit irgendwo im Hinterkopf zu behalten. –

+0

@JohnBollinger - Sehr wahr. Es ist auch gut zu beachten, dass Sie anstelle eines einzelnen Zeichenbegrenzers eine beliebige Zeichenfolge verwenden können. Zum Beispiel hätte ich anstelle von '|' 'StackOverflowIsAwesome ~' verwenden können. –

+0

Es hat funktioniert ... Du bist ein Genie. – Tpi

0

Ihr XPath-Ausdruck ./MySegment/*[not(.=preceding::*)] wählt diese untergeordneten Elemente von jedem der <MySegment> Kinderkontextknoten, deren String-Werte in der Dokumentreihenfolge vorangehenden sie nicht mit denen von jedes Elemente entsprechen. Somit wird das <Field2>ABC</Field2> aufgrund der vorhergehenden <Field1>ABC</Field1> Elemente im Ergebnis nicht wiedergegeben.

Offensichtlich ist das eine breitere Bedingung, als Sie beabsichtigen; So wie ich es verstehe, möchten Sie nur mit vorhergehenden Elementen gleichen Namens vergleichen. Das ist ein bisschen schwierig, in reinem XPath auszudrücken; es wäre einfacher, mit einem Stylesheet-Refactoring umzugehen. Eine unbegründete Verwendung von xsl:for-each schlägt auf jeden Fall ein solches Refactoring vor. Hier ist ein vernünftiger Weg:

<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="/RecordsInp/ParentSegment/MySegment/*"> 
    <!-- bind the context node's name and value to variables: --> 
    <xsl:variable name="fname" select="name()"/> 
    <xsl:variable name="fvalue" select="string(.)"/> 

    <!-- here's the test you seem really to want: --> 
    <xsl:if test="not(preceding::*[name() = $fname and string() = $fvalue])"> 
     <A> 
     <Field1><xsl:value-of select ="$fname"/></Field1> 
     <Field2><xsl:value-of select="$fvalue"/></Field2> 
     </A> 
    </xsl:if> 
    </xsl:template> 

</xsl:stylesheet> 
Verwandte Themen