<Rootnode>
<Properties Attribute ="xxx">
<Type>1</Type>
<Size>10</Size>
</Properties>
<Other>
<blah>h</blah>
</Other>
<Other2>
<blah>h</blah>
</Other2>
<Properties Attribute ="xxx">
<xType>5</xType>
<xSize>10</xSize>
</Properties>
<Items>
<Item4>8</Item4>
</Items>
<Items>
<Item6>8</Item6>
</Items>
<Properties Attribute ="xxx">
<zType>1</zType>
<zSize>10</zSize>
</Properties>
<Items place="UK">
<Item1>8</Item1>
</Items>
</Rootnode>
Teraz chcę tylko TYLKO Właściwościi przedmioty. Najlepiej połączyć ze sobą grupy Właściwości i Elementy, jeśli Atrybuty mają tę samą nazwę i tę samą wartość, oraz SORTOWAĆ zarówno Właściwości, jak i Elementy na podstawie Atrybutów oraz posortować węzły podrzędne alfabetycznie. Do tej pory osiągnąłem puste; (
Wymagana wydajność jest prawie taka, jak pokazał ABach. Chociaż jedną rzeczą, o której zapomniałem wspomnieć, jest to, że mogą istnieć inne atrybuty dla każdej Właściwości lub Przedmiotów i że znam nazwę Atrybutu, na którym chcę sortować. Że mogę łatwo zmienić.
tj. wymagana wydajność
<?xml version="1.0"?>
<Rootnode>
<Properties Attribute="xxx">
<Size>10</Size>
<Type>1</Type>
<xSize>10</xSize>
<xType>5</xType>
<zSize>10</zSize>
<zType>1</zType>
</Properties>
<Items>
<Item4>8</Item4>
<Item6>8</Item6>
</Items>
<Items place="UK">
<Item1>8</Item1>
</Items>
</Rootnode>
I przepraszam za dotychczasowy wysiłek ... Skończyło się na właściwym bałaganie i nie sądziłem, że to bardzo by pomogło ... Jestem całkiem nowy w tych sprawach :)
Odpowiedzi:
2 dla odpowiedzi № 1Jak już wskazał @LarsH, nie pokazując nam oczekiwanego wyjściowego pliku XML, pozostajemy zgadnąć, czego naprawdę chcesz. To powiedziawszy, oto moja próba rozwiązania XSLT 1.0.
Kiedy ten XSLT:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output omit-xml-declaration="no" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:key
name="PropertiesByAttributeNameVal"
match="Properties"
use="concat(name(@*[1]), "+", @*[1])" />
<xsl:key
name="ItemsByAttributeNameVal"
match="Items"
use="concat(name(@*[1]), "+", @*[1])" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="Rootnode">
<Rootnode>
<xsl:apply-templates
select="Properties[
generate-id() =
generate-id(key(
"PropertiesByAttributeNameVal",
concat(name(@*[1]), "+", @*[1]))[1])]">
<xsl:with-param name="pKeyName"
select=""PropertiesByAttributeNameVal"" />
<xsl:sort select="concat(name(@*[1]), "+", @*[1])" />
</xsl:apply-templates>
<xsl:apply-templates
select="Items[
generate-id() =
generate-id(key(
"ItemsByAttributeNameVal",
concat(name(@*[1]), "+", @*[1]))[1])]">
<xsl:with-param name="pKeyName"
select=""ItemsByAttributeNameVal"" />
<xsl:sort select="concat(name(@*[1]), "+", @*[1])" />
</xsl:apply-templates>
</Rootnode>
</xsl:template>
<xsl:template match="Properties|Items">
<xsl:param name="pKeyName" />
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates
select="key($pKeyName, concat(name(@*[1]), "+", @*[1]))/*">
<xsl:sort select="name()" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
... uruchom z dostarczonym plikiem XML:
<Rootnode>
<Properties Attribute="xxx">
<Type>1</Type>
<Size>10</Size>
</Properties>
<Other>
<blah>h</blah>
</Other>
<Other2>
<blah>h</blah>
</Other2>
<Properties Attribute="xxx">
<xType>5</xType>
<xSize>10</xSize>
</Properties>
<Items>
<Item4>8</Item4>
</Items>
<Items>
<Item6>8</Item6>
</Items>
<Properties Attribute="xxx">
<zType>1</zType>
<zSize>10</zSize>
</Properties>
<Items place="UK">
<Item1>8</Item1>
</Items>
</Rootnode>
... myślę, że poprawne dane wyjściowe XML jest generowany:
<?xml version="1.0"?>
<Rootnode>
<Properties Attribute="xxx">
<Size>10</Size>
<Type>1</Type>
<xSize>10</xSize>
<xType>5</xType>
<zSize>10</zSize>
<zType>1</zType>
</Properties>
<Items>
<Item4>8</Item4>
<Item6>8</Item6>
</Items>
<Items place="UK">
<Item1>8</Item1>
</Items>
</Rootnode>
Pamiętaj, że jeśli ten sam XSLT jest uruchamiany na nieco zmodyfikowanym dokumencie XML (który ma więcej grupowań itp.):
<?xml version="1.0" encoding="utf-8"?>
<Rootnode>
<Properties Attribute="xxx">
<Type>1</Type>
<Size>10</Size>
</Properties>
<Other>
<blah>h</blah>
</Other>
<Other2>
<blah>h</blah>
</Other2>
<Properties Attribute="yyy">
<xType>5</xType>
<xSize>10</xSize>
</Properties>
<Items>
<Item4>8</Item4>
</Items>
<Items place="US">
<Item9>8</Item9>
</Items>
<Items>
<Item1>8</Item1>
</Items>
<Properties Attribute2="xxx">
<zType>1</zType>
<zSize>10</zSize>
</Properties>
<Properties Attribute="xxx">
<elephantType>5</elephantType>
<elephantSize>15</elephantSize>
</Properties>
<Items place="UK">
<Item1>8</Item1>
</Items>
</Rootnode>
... znowu, zakładam, że otrzymano prawidłową odpowiedź:
<?xml version="1.0"?>
<Rootnode>
<Properties Attribute="xxx">
<Size>10</Size>
<Type>1</Type>
<elephantSize>15</elephantSize>
<elephantType>5</elephantType>
</Properties>
<Properties Attribute="yyy">
<xSize>10</xSize>
<xType>5</xType>
</Properties>
<Properties Attribute2="xxx">
<zSize>10</zSize>
<zType>1</zType>
</Properties>
<Items>
<Item1>8</Item1>
<Item4>8</Item4>
</Items>
<Items place="UK">
<Item1>8</Item1>
</Items>
<Items place="US">
<Item9>8</Item9>
</Items>
</Rootnode>
Założenia:
- Zakładam, że każdy
<Properties>
i<Items>
element ma tylko jeden atrybut i powinien to być determinant grupowania. - Jeśli powyższe nie jest prawdą, przynajmniej zakładam, że pierwszym atrybutem tego elementu powinien być determinant grupowania.
Wyjaśnienie:
Ponieważ jest to rozwiązanie XSLT 1.0,
Muenchian Grouping
jest kolejnością dnia, w której grupowanie węzłów i atrybutów w ramach unikalnych selektorów; dlatego definiujemy dwa klucze: jeden dla<Properties>
elementy i jeden dla<Items>
elementy.Pierwszy szablon to
Identity Transform
- jego zadaniem jest wyprowadzenie wszystkich węzłów i atrybutów z dokumentu źródłowego do dokumentu wynikowego w niezmienionej postaci.Drugi szablon pasuje do
<Rootnode>
element. Poleca się stosowanie szablonów tylko do tych<Properties>
i<Items>
elementy, które jako pierwsze pojawiają się w odpowiednich klawiszach; ma to zamierzony efekt przetwarzania tylko unikatowych elementów (na podstawie nazwy i wartości ich pierwszego atrybutu).Kiedy
<xsl:apply-templates>
element jest określony, należy pamiętać, że w obu przypadkach nakazuje się sortowanie wyników według tej samej pary nazwa / wartość atrybutu.Zauważ, że każdy
<xsl:apply-templates>
element otrzymuje parametr (przez<xsl:with-param>
). Jak zobaczysz, kod do przetworzenia obu<Properties>
i<Items>
elementy są prawie identyczne; jedyna różnicajest kluczem, z którego czerpiemy wyniki. Z tego powodu postanowiłem skonsolidować tę logikę w trzecim szablonie i uwzględnić zmienność za pomocą tego parametru.Trzeci szablon pasuje do obu
<Properties>
i<Items>
elementy. Dla każdego oryginalny węzeł jest kopiowany (podobnie jak jego atrybuty). Na koniec szablony są stosowane wobec wszystkich elementów potomnych tego elementu (z zachowaniem odpowiedniego sortowania [tym razem na podstawie nazwy samego elementu potomnego]).
1 dla odpowiedzi nr 2
Bardziej prawdopodobne jest, że otrzymasz pomoc, jeśli masz już coś, niż nic. Aby rozpocząć, utwórz szablon, który będzie pasował do właściwości i elementów (match="Properties | Items"
), którego treść kopiuje tylko dopasowany element: <xsl:copy-of select="." />
.
To da ci jakiś działający kod do pokazania.
Następnym krokiem, który zasugerowałbym, jest opublikowanie próbki pożądanego wyniku i faktycznego wyniku podanego przez kod XSLT.
Zapewni to znacznie mniejszą lukę dla osób, które mogą wypełnić odpowiedź na twoje pytanie.