chrisen
Goto Top

XML - XSLT Formatierung mehrere verschiedene Werte

Hallo zusammen,
ich habe eine Frage zur Konvertierung eines XML Dokuments mit XSLT in ein anderes XML Dokument.

Es geht darum irgendwie eine Abfrage mit herein zu bekommen, die das folgendes Problem löst.

Code der Konvertiert werden soll:

<?xml version="1.0" standalone="yes"?>  
<DocumentElement>
  <article>
    <ordernumber>Nummer</ordernumber>
    <mainnumber>Nummer</mainnumber>
    <ItmsGrpNam>Art</ItmsGrpNam>
    <name>Name</name>
    <suppliername>Hersteller</suppliername>
    <active>1</active>
    <Price>0.000000</Price>
    <propertyGroupName>1A</propertyGroupName>
    <propertyOptionName>1B</propertyOptionName>
    <propertyValueName>1C</propertyValueName>
    <propertyGroupName>2A</propertyGroupName>
    <propertyOptionName1>2B</propertyOptionName1>
    <propertyValueName1>2C</propertyValueName1>
    <propertyGroupName>3A</propertyGroupName>
    <propertyOptionName2>3B</propertyOptionName2>
    <propertyValueName2>3C</propertyValueName2>
  </article>
</DocumentElement>

Es geht um die Auflistung der Propertys (Group, Option,Value).

Diese sollten danach so aussehen:

<propertyValue>
		<propertyGroupName>1A</propertyGroupName>
		<propertyValueName>1B</propertyValueName>
		<propertyOptionName>1C</propertyOptionName>
</propertyValue>
<propertyValue>
		<propertyGroupName>2A</propertyGroupName>
		<propertyValueName>2B</propertyValueName>
		<propertyOptionName>2C</propertyOptionName>
</propertyValue>
<propertyValue>
		<propertyGroupName>3A</propertyGroupName>
		<propertyValueName>3B</propertyValueName>
		<propertyOptionName>3C</propertyOptionName>
</propertyValue>

Bein bisheriger Ansatz ist der hier:

<?xml version="1.0" encoding="UTF-8"?>  
<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="/">  
  <Root>
  <articles>
    <xsl:for-each select="DocumentElement/article">  
      <article>
	  <ordernumber><xsl:value-of select="ordernumber"/></ordernumber>  
	  <mainnumber><xsl:value-of select="mainnumber"/></mainnumber>  
	  <name><xsl:value-of select="name"/></name>  
	  <supplier><xsl:value-of select="suppliername"/></supplier>  
	  <tax>19</tax>
	  <prices>
	  <price>
		<price><xsl:value-of select="Price"/></price>  
	  </price>
	  </prices>
	  <active><xsl:value-of select="active"/></active>  
	  <category>
		<categories>
		<xsl:choose>
		<xsl:when test="ItmsGrpNam='Lager'">39</xsl:when>  
		<xsl:when test="ItmsGrpNam='Transistor'">40</xsl:when>  
		<xsl:when test="ItmsGrpNam='Dichtring'">41</xsl:when>  
		<xsl:when test="ItmsGrpNam='Schütz'">42</xsl:when>  
		</xsl:choose>
		
		</categories>
		</category>
		<propertyValue>
			<propertyGroupName><xsl:value-of select="propertyGroupName"/> </propertyGroupName>  
			<propertyOptionName><xsl:value-of select="propertyOptionName"/></propertyOptionName>  
			<propertyValueName><xsl:value-of select="propertyValueName"/></propertyValueName>  
		</propertyValue>
      </article>
    </xsl:for-each>
    </articles>
  </Root>
</xsl:template>
</xsl:stylesheet>

Das gibt natürlich nur den ersten Wert wieder raus:
<propertyValue>
		<propertyGroupName>1A</propertyGroupName>
		<propertyOptionName>1B</propertyOptionName>
		<propertyValueName>1C</propertyValueName>
</propertyValue>

Gibt es dafür eine Lösung?

Freue mich über euere Antworten!

Grüße,
chrisen

Content-ID: 314026

Url: https://administrator.de/contentid/314026

Ausgedruckt am: 04.12.2024 um 18:12 Uhr

colinardo
Lösung colinardo 31.08.2016, aktualisiert am 01.09.2016 um 16:03:56 Uhr
Goto Top
Hallo chrisen,
für XSLT v1.0 habe ich im Moment leider keinen Code, aber für XSLT v2.0 (ACHTUNG: nicht vom NET Framework und meinen vorherigen Skripten unterstützt) bei dem man mehr Möglichkeiten zur Gruppierung hat (for-each-group), sieht das ganze so aus:
<?xml version="1.0" encoding="UTF-8"?>  
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">  
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />  
<xsl:template match="/">  
  <Root>
  <articles>
    <xsl:for-each select="DocumentElement/article">  
      <article>
	  <ordernumber><xsl:value-of select="ordernumber"/></ordernumber>  
	  <mainnumber><xsl:value-of select="mainnumber"/></mainnumber>  
	  <name><xsl:value-of select="name"/></name>  
	  <supplier><xsl:value-of select="suppliername"/></supplier>  
	  <tax>19</tax>
	  <prices>
	  <price>
		<price><xsl:value-of select="Price"/></price>  
	  </price>
	  </prices>
	  <active><xsl:value-of select="active"/></active>  
	  <category>
		<categories>
		<xsl:choose>
		<xsl:when test="ItmsGrpNam='Lager'">39</xsl:when>  
		<xsl:when test="ItmsGrpNam='Transistor'">40</xsl:when>  
		<xsl:when test="ItmsGrpNam='Dichtring'">41</xsl:when>  
		<xsl:when test="ItmsGrpNam='Schütz'">42</xsl:when>  
		</xsl:choose>
		
		</categories>
		</category>
		<xsl:for-each-group select="*[starts-with(local-name(),'property')]" group-starting-with="*[starts-with(local-name(),'propertyGroupName')]">  
		   <propertyValue>
			<propertyGroupName><xsl:value-of select="current-group()[1]" /></propertyGroupName>  
			<propertyValueName><xsl:value-of select="current-group()[2]" /></propertyValueName>  
			<propertyOptionName><xsl:value-of select="current-group()[3]" /></propertyOptionName>  
		   </propertyValue>
		</xsl:for-each-group>
      </article>
    </xsl:for-each>
    </articles>
  </Root>
</xsl:template>
</xsl:stylesheet>
Kannst du z.B. hier testen.

Eine Bibliothek für XSLT 2.0 bekommst zu z.B. hier:
http://saxon.sourceforge.net/#F9.7HE

In der Community-Edition von AltovaXML ist auch ein Commandline-Processor für xslt2 enthalten.
Die Community Edition kannst du hier herunterladen.

Damit kannst du die Transformation dann so in der CMD durchführen:
AltovaXML.exe /xslt2 "C:\tranform.xsl" -in "C:\input.xml" -out "C:\output.xml"
Oder wenn die Community Edition installiert ist kannst du die Bibliothek auch per .NET in Powershell ansprechen:
Add-Type -Path "C:\Program Files (x86)\Altova\AltovaXML2013\Altova.AltovaXML.dll"  
$class = New-Object Altova.AltovaXML.ApplicationClass
$class.XSLT2.InputXMLFileName = 'C:\input.xml'  
$class.XSLT2.XSLFileName = 'C:\transform.xsl'  
$class.XSLT2.Execute('C:\output.xml')  
Oder auch per COM-Object und VBS/VBA:
set xml = CreateObject("AltovaXML.Application")  
xml.XSLT2.InputXMLFileName = "C:\input.xml"  
xml.XSLT2.XSLFileName = "C:\transform.xsl"  
xml.XSLT2.Execute("C:\output.xml")  
Grüße Uwe

p.s. Ach ja, bevor ich's vergesse, vielen Dank für deine Spende! face-smile
colinardo
colinardo 31.08.2016 aktualisiert um 14:31:39 Uhr
Goto Top
Zur Info, habe meinen Post oben noch ergänzt.
chrisen
chrisen 31.08.2016 um 15:31:15 Uhr
Goto Top
Hallo colinardo,

nochmal vielen Dank für deine Antwort!!

Ich versuche gerade die Bibliothek für XLST 2.0 zu installieren. Habe damit aber noch ein paar Probleme

Grüße,
chrisen

p.s. gerne ;) und danke nochmal für deine ganze Hilfe!
colinardo
colinardo 31.08.2016 aktualisiert um 15:35:03 Uhr
Goto Top
Ich versuche gerade die Bibliothek für XLST 2.0 zu installieren. Habe damit aber noch ein paar Probleme
Nimm die Altova-Community-Edition wie oben beschrieben, die ist am unkompliziertesten einzurichten. Installer starten, feddich.
chrisen
chrisen 31.08.2016 aktualisiert um 15:55:30 Uhr
Goto Top
Zitat von @colinardo:
Nimm die Altova-Community-Edition wie oben beschrieben, die ist am unkompliziertesten einzurichten. Installer starten, feddich.

Habe ich aber dann kommt immer eine Fehlermeldung: ActiveX Komponente kann kein Objekt erstellen: 'AltovaXML.Application'.
(Wenn ich das VBScript laufen lasse)
colinardo
Lösung colinardo 31.08.2016 aktualisiert um 16:31:30 Uhr
Goto Top
Dann hast du es nicht mit Admin-Rechten installiert! Du kannst die Registrierung auch nach der Installation nachholen indem du in einer administrativen cmd in das Verzeichnis navigierst und dort den Registrierungsvorgang wiederholst
cd "C:\Program Files (x86)\Altova\AltovaXML2013"  
AltovaXML_COM.exe /regserver
Klappt das nicht, Rechner neu starten oder du machst noch was anderes falsch. Funktioniert hier unter Win7-10 wie immer einwandfrei. Virenscanner mal vorher deaktivieren.

Aber wie oben geschrieben kannst du auch direkt die exe von altova dazu verwenden (s. Beispiel oben), dann brauchst du kein VBS.
chrisen
chrisen 31.08.2016 aktualisiert um 18:33:09 Uhr
Goto Top
Super jetzt funktioniert es!
Hatte die Version 2016 installiert, mit der es anscheinend nicht funktioniert hat.
colinardo
colinardo 31.08.2016 aktualisiert um 18:59:08 Uhr
Goto Top
Zitat von @chrisen:
Super jetzt funktioniert es!
Naturalmente il mio amico.
Hatte die Version 2016 installiert, mit der es anscheinend nicht funktioniert hat.
Wozu schreibe ich die Anleitung und poste den korrekten und einzigen Link wenn du sie nicht exakt befolgst und irgendwas anderes runterlädst face-smile?! Eine 2016er Variante davon gab es nie, gäbe es sie, hätte ich diese verlinkt. Die kostenlose Community Edition ist auch nicht mehr bei Altova auf der Webseite gelistet, trotzdem kann man sie noch herunterladen. Was du da geladen hast, weiß der Geier face-wink.

Als denn frohes Schaffen noch
Uwe
chrisen
chrisen 01.09.2016 aktualisiert um 13:36:18 Uhr
Goto Top
Zitat von @colinardo:
Hatte die Version 2016 installiert, mit der es anscheinend nicht funktioniert hat.
Wozu schreibe ich die Anleitung und poste den korrekten und einzigen Link wenn du sie nicht exakt befolgst und irgendwas anderes runterlädst face-smile?! Eine 2016er Variante davon gab es nie, gäbe es sie, hätte ich diese verlinkt. Die kostenlose Community Edition ist auch nicht mehr bei Altova auf der Webseite gelistet, trotzdem kann man sie noch herunterladen. Was du da geladen hast, weiß der Geier face-wink.


Alles klar sorry face-smile

Ich hätte noch eine kurze Frage:
Und zwar klappt das Script nicht immer.

Bsp. hier:

XML:

<?xml version="1.0" standalone="yes"?>  
<DocumentElement>
  <article>
    <ordernumber>100096</ordernumber>
    <mainnumber>100096</mainnumber>
    <ItmsGrpNam>Gruppenname</ItmsGrpNam>
    <name>Name</name>
    <suppliername>Hersteller</suppliername>
    <PackUnit />
    <active>1</active>
    <Price>0.000000</Price>
    <propertyGroupName3>1A</propertyGroupName3>
    <propertyOptionName3>1B</propertyOptionName3>
    <propertyValueName3>1C</propertyValueName3>
    <propertyGroupName4>2A</propertyGroupName4>
    <propertyOptionName4>2B</propertyOptionName4>
    <propertyValueName4>2C</propertyValueName4>
    <propertyGroupName5>3A</propertyGroupName5>
    <propertyOptionName5>3B</propertyOptionName5>
    <propertyValueName5>3C</propertyValueName5>
    <propertyGroupName7>4A</propertyGroupName7>
    <propertyOptionName7>4B</propertyOptionName7>
    <propertyValueName7>4C</propertyValueName7>
  </article>
</DocumentElement>

XSL:

<?xml version="1.0" encoding="UTF-8"?>  
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">  
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />  
<xsl:template match="/">  
  <Root>
  <articles>
    <xsl:for-each select="DocumentElement/article">  
      <article>
	  <ordernumber><xsl:value-of select="ordernumber"/></ordernumber>  
	  <mainnumber><xsl:value-of select="mainnumber"/></mainnumber>  
	  <name><xsl:value-of select="name"/></name>  
	  <supplier><xsl:value-of select="suppliername"/></supplier>  
	  <tax>19</tax>
	  <prices>
	  <price>
		<price><xsl:value-of select="Price"/></price>  
	  </price>
	  </prices>
	  <active><xsl:value-of select="active"/></active>  
	  <category>
		<categories>
		<xsl:choose>
		<xsl:when test="ItmsGrpNam='Kat1'">39</xsl:when>  
		<xsl:when test="ItmsGrpNam='Kat2'">40</xsl:when>  
		<xsl:when test="ItmsGrpNam='Kat3'">41</xsl:when>  
		<xsl:when test="ItmsGrpNam='Kat4'">42</xsl:when>  
		</xsl:choose>
		
		</categories>
		</category>
		<xsl:for-each-group select="*[starts-with(local-name(),'property')]" group-ending-with="*[position() mod 3 = 1]">  
		   <propertyValue>
			<propertyGroupName><xsl:value-of select="current-group()[1]" /></propertyGroupName>  
			<propertyOptionName><xsl:value-of select="current-group()[2]" /></propertyOptionName>  
			<propertyValueName><xsl:value-of select="current-group()[3]" /></propertyValueName>  
		   </propertyValue>
		</xsl:for-each-group>
      </article>
    </xsl:for-each>
    </articles>
  </Root>
</xsl:template>
</xsl:stylesheet>

Ergebnis:

<?xml version="1.0" encoding="UTF-8"?>  
<Root>
   <articles>
      <article>
         <ordernumber>100096</ordernumber>
         <mainnumber>100096</mainnumber>
         <name>Name</name>
         <supplier>Hersteller</supplier>
         <tax>19</tax>
         <prices>
            <price>
               <price>0.000000</price>
            </price>
         </prices>
         <active>1</active>
         <category>
            <categories/>
         </category>
         <propertyValue>
            <propertyGroupName>1A</propertyGroupName>
            <propertyOptionName>1B</propertyOptionName>
            <propertyValueName/>
         </propertyValue>
         <propertyValue>
            <propertyGroupName>1C</propertyGroupName>
            <propertyOptionName>2A</propertyOptionName>
            <propertyValueName>2B</propertyValueName>
         </propertyValue>
         <propertyValue>
            <propertyGroupName>2C</propertyGroupName>
            <propertyOptionName>3A</propertyOptionName>
            <propertyValueName>3B</propertyValueName>
         </propertyValue>
         <propertyValue>
            <propertyGroupName>3C</propertyGroupName>
            <propertyOptionName>4A</propertyOptionName>
            <propertyValueName>4B</propertyValueName>
         </propertyValue>
         <propertyValue>
            <propertyGroupName>4C</propertyGroupName>
            <propertyOptionName/>
            <propertyValueName/>
         </propertyValue>
      </article>
   </articles>
</Root>

Woran kann das liegen?
colinardo
colinardo 01.09.2016 aktualisiert um 14:48:00 Uhr
Goto Top
Hmm, kann ich hier nicht bestätigen. Das ist eine simple Gruppierung der Nodes die mit property beginnen in der Reihenfolge wie sie im XML Code stehen gruppiert wird dann durch die Berechnung der Position welche nach jeder 3 Position eine neue Gruppe beginnen lässt.
chrisen
chrisen 01.09.2016 um 15:18:04 Uhr
Goto Top
Merkwürdigerweise passiert das auch in dem online Transformator.
colinardo
colinardo 01.09.2016 aktualisiert um 16:04:55 Uhr
Goto Top
Ach, Asche auf mein Haupt, die position() hat sich auf die falschen Nodes bezogen, Fehler ist oben korrigiert, sorry.
chrisen
chrisen 01.09.2016 um 16:17:40 Uhr
Goto Top
Ach Super!! Vielen vielen Dank!!