2012-11-09 12 views
9

Mam XML z wieloma węzłami z podobnymi danymi w każdym. Chcę usunąć określony atrybut z każdego węzła (USER: IPADDRESS). Mam zorientowali się, jak łańcuch razem szereg elementów przy użyciu RNO prostu opuszczając user = „{@} użytkownika” mecz, więc nie pojawiają się w wynikach:XSLT: użyj wielu lub więcej szablonów do zastosowania-szablonów

XSL Snippet:

<xsl:template match="Creation | Test | Assignment | Modification | Repair | Termination"> 
<Creation CommitID="{@CommitID}" Date="{@Date}" BoardID="{@BoardID}"> 
<xsl:apply-templates/> 
</Creation> 
</xsl:template> 

Jak można się domyślić, wszystkie nazwy węzłów po "Creation" zostają ponownie nazwane Creation, ponieważ właśnie to mam zamiar zrobić. Jak przekazać różne mecze, aby zostały one zastosowane we właściwej kolejności w wynikach? Wiem, że potrafię zrobić brutalną siłę używając identycznych instrukcji XSL dla każdego z różnych meczów (tak to zrobiłem za pierwszym razem), ale musi być bardziej elegancka metoda, po prostu mnie unika. Mam miliony & milionów linii XML do przetworzenia i jest to tylko pierwsza z wielu transformacji, które będę musiał wykonać.

Używam msxsl V4.0 na polu Win7, aby wykonać moje transformacje, jeśli ma to jakiekolwiek znaczenie.

XML:

<?xml version="1.0"?> 
<BoardDatabase> 
<Board_Data BoardID="1035"> 
    <Creation CommitID="12b" Date="2007-12-07T15:43:51" BoardID="1035" User="CSAGAN:192.168.1.177"> 
     <BoardDrawing>3B</BoardDrawing> 
     <AssemblyDrawing>2010F</AssemblyDrawing> 
     <Notes>PO Num 1959</Notes> 
    </Creation> 
    <Test CommitID="117" Date="2007-12-10T10:39:43" BoardID="1035" User="CSAGAN:192.168.1.183"> 
     <ElectricalTestData Result="FAIL" Version="IMM STD REVF"> 
      <AutomatedTest ReportVersion="1.0"> 
       <TestSetup> 
        <TestAppBuildDate>Dec 07 2007</TestAppBuildDate> 
        <VersionPath>c:\tests\versions\v12.txt</VersionPath> 
        <VersionNumber>1.2</VersionNumber> 
        <OperatorName>CSAGAN</OperatorName> 
        <StationID>PC-191-NDGrasse</StationID> 
        <JigSN>12345</JigSN> 
        <JigAssembly>42</JigAssembly> 
        <TestStartTime>2007-12-10 10:34:17</TestStartTime> 
       </TestSetup> 
      </AutomatedTest> 
     </ElectricalTestData> 
    </Test> 
    <Assignment CommitID="1c1f" User="JRandi:192.168.1.162" Date="2008-09-30T07:36:52" BoardID="1035"> 
     <Notes>Boardset failed etest twice, no problem log entry/repair attempts made.</Notes> 
    </Assignment> 
    <Modification CommitID="2bb7" User="JRandi:192.168.1.162" Date="2009-03-11T13:31:21" BoardID="1035"> 
     <AssemblyDrawing>2001G</AssemblyDrawing> 
     <Notes>Cornelius upgraded boardset to rev. G</Notes> 
    </Modification> 
</Board_Data> 
</BoardDatabase> 

XSL:

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

<xsl:template match="Creation | Test | Assignment | Modification | Repair | Termination"> 
<Creation CommitID="{@CommitID}" Date="{@Date}" BoardID="{@BoardID}"> 
<xsl:apply-templates/> 
</Creation> 
</xsl:template> 

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

Najnowsze XSL przy użyciu @ rozwiązania DevNull że podwaja rozmiar oryginalnego pliku:

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

<!-- Answer from Stack Overflow that only strips out the IP Address from the User attribute. --> 
<xsl:template match="@User"> 
    <xsl:attribute name="User"> 
    <xsl:value-of select="substring-before(.,':')"/> 
    </xsl:attribute> 
</xsl:template> 

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

Najnowsze XSL od @ rozwiązania Dimitre że trwa bardzo długi czas przetwarzania (nadal trwa po ponad 30 minutach, ale plik wciąż rośnie):

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

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

<xsl:template match= 
    "*[contains('|Creation|Test|Assignment|Modification|Repair|Termination|',concat('|', name(), '|')) 
]/@user"/> 
</xsl:stylesheet> 
+0

+1 Ładnie napisane pytanie. –

+0

Dobre pytanie, +1. Być może zainteresuje Cię nieco lepsze rozwiązanie, które jest krótsze i można je przystosować do nieskończenie długiej listy nazw elementów - które nawet mogłyby zostać przekazane jako parametr transformacji. –

Odpowiedz

15

Spróbuj zmienić szablon do tego:

<xsl:template match="Creation|Test|Assignment|Modification|Repair|Termination"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*[not(name()='User')]|node()"/> 
    </xsl:copy> 
</xsl:template> 

Zauważysz, że wygląda trochę jak szablon tożsamości z orzecznika dodanego do @*.

Ponadto, jeśli chciał rozebrać wszystkie User atrybuty bez względu element był, można użyć tego szablonu zamiast:

<xsl:template match="@User"/> 

Oto jeszcze jeden sposób (tylko odpędzania z Creation i Test dla zwięzłość)

<xsl:template match="@User[..[self::Creation or self::Test]]"/> 

Odpowiedź na komentarz

Użyj tego szablonu zamiast:

<xsl:template match="@User"> 
    <xsl:attribute name="User"> 
     <xsl:value-of select="substring-before(.,':')"/> 
    </xsl:attribute> 
</xsl:template> 
+0

Idealnie! Dzisiaj po raz pierwszy używam XSLT, więc wchodzę na zakręt i wiem, że muszę się jeszcze wiele nauczyć. Dosłownie przechodzę teraz przez "XSLT For Dummies". Dzięki za szybką odpowiedź. – delliottg

+2

@delliottg - Dobra robota do tej pory. Jesteś na dobrej drodze, używając transformacji tożsamości, a następnie zmieniając ją, gdy zachodzi taka potrzeba. Wielu początkujących od razu przechodzi do 'xsl: for-each' :-) Dodam też inną opcję, którą możesz użyć tylko dla odmiany. –

+0

To prawdopodobnie powinno być inne pytanie, ale co, gdybym po prostu chciał usunąć adresy IP z każdego atrybutu użytkownika? Zatem Użytkownik = "JRandi: 192.168.1.162" stanie się Użytkownikiem = "JRandi". Re: xsl: za każdym razem spędziłem dużo czasu wczoraj i dzisiaj czytając odpowiedzi od ludzi takich jak Dimitre Novatchev i Tomalak i dowiedziałem się, że to nie jest dobra droga. – delliottg

2

użyłbym co uważam nawet lepsze rozwiązanie:

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

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

<xsl:template match= 
"*[contains('|Creation|Test|Assignment|Modification|Repair|Termination|', 
      concat('|', name(), '|')) 
    ]/@user"/> 
</xsl:stylesheet> 

Należy pamiętać:

  1. tylko My używać pojedynczego szablonu zastępującego tożsamość reguła. Jego ciało jest puste.

  2. Lista nazw elementów przedstawiona jest jako ciąg rozdzielany potokami, a dla długich list oszczędza znaczną przestrzeń - również taki ciąg może być przekazany jako parametr zewnętrzny do transformacji, dzięki czemu jest on maksymalnie uniwersalny.

  3. Ta transformacja jest całkowicie "push-style".

+0

dzięki za rozwiązanie. Mam kilka pytań, używam tego przeciwko dość dużemu plikowi (140mb) i działa już ponad 10 minut (nie jestem do końca pewien, kiedy zacząłem), gdzie rozwiązanie DevNulla działa w mniej niż minutę. Widzę, że twoje rozwiązanie wciąż jest przetwarzane, ponieważ widzę, że rozmiar pliku wynikowego rośnie, ale zajmuje to dużo czasu. Czy masz pomysł, dlaczego różnica czasu jest tak duża? Są też problemy z inną transformacją, proszę zobaczyć moje komentarze do tego. – delliottg

+0

@delliottg, oba rozwiązania powinny mieć mniej więcej taką samą wydajność. Mam wrażenie, że próbujesz dostosować te rozwiązania do innego formatu XML i prawdopodobnie nie wykonasz tej adaptacji we właściwy sposób. Zaleca się dostarczenie w pełni reprezentatywnego (ale niewielkiego) źródłowego dokumentu XML i dokładnie pożądanego rezultatu - wtedy moglibyśmy podać rozwiązanie, które nie wymaga adaptacji. –

+0

Próbowałem zrobić to dokładnie z pewnym zaciemnieniem danych, imionami itp., Jak również mocno skróconym plikiem z przykładem każdego typu "CommitID" w przykładowym pliku. Format podanego przeze mnie przykładu jest bardzo zbliżony do rzeczywistych danych (których nie mogę podać ze względu na ograniczenia firmy), jednak nie mogę znieść, że mogą istnieć pewne rzeczy w danych, których nie znam (tylko tu 4 tygodnie), a pliki są ogromne. Poświęcę trochę czasu, aby skonstruować pełniejszy przykład XML i dołączyć go do pierwotnego pytania. Dziękuję za pomoc, doceniam to. – delliottg

Powiązane problemy