Настоящим продолжением вопроса , размещенного здесь в прошлом году. Все еще будучи новичком, я изо всех сил пытаюсь (снова...) преобразовать - используя XSLT 1.0 - следующий XML, который описывает объекты (обратите внимание на небольшое изменение ввода - "BC *" - на предыдущий вопрос):
<Data>
<Object>
<Property Name="Id" Value="001"/>
<Property Name="P.Id" Value="Id P"/>
<Property Name="P.Description" Value="Descr P"/>
<Property Name="A.Id" Value="Id A" />
<Property Name="A.Description" Value="Descr A"/>
<Property Name="B.Id" Value="Id B"/>
<Property Name="B.Description" Value="Descr B"/>
<Property Name="B.C.Id" Value="B.C.Id"/>
<Property Name="B.C.Description" Value="B.C.Description"/>
</Object>
</Data>
Для получения желаемого результата должны применяться следующие правила:
- Для каждого элемента 'Property', который не содержит разделитель '.' в атрибуте «Имя» преобразовать атрибут «Имя» в дочерний элемент и выбрать значение его атрибута «Значение».
- For each 'Property'-element that does contain separator(s) '.' in the 'Name'-attribute, create:
- a) a (grand)parent element using 'substring-before' the separator in the 'Name'-attribute - 'recursively until the last occurence' (not sure how to describe; see desired output below), and
- б) дочерний элемент, использующий «подстроку-после» последнего разделителя в атрибуте «Имя» и выбирает значение его атрибута «Значение».
Таким образом, желаемый результат должен выглядеть примерно так:
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<ObjectData>
<Id>001</Id>
<P>
<Id>Id P</Id>
<Description>Descr P</Description>
</P>
<A>
<Id>Id A</Id>
<Description>Descr A</Description>
</A>
<B>
<Id>Id B</Id>
<Description>Descr B</Description>
<C>
<Id>B.C.Id</Id>
<Description>B.C.Description</C.Description>
</C>
</B>
</ObjectData>
</Root>
В настоящее время у меня есть следующий код:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:key name="kPropertyByName" match="Property[contains(@Name, '.')]" use="concat(generate-id(..), '|', substring-before(@Name,'.'))"/>
<xsl:template match="Data">
<Root>
<xsl:apply-templates/>
</Root>
</xsl:template>
<xsl:template match="Object">
<ObjectData>
<xsl:apply-templates select="Property[not(contains(@Name, '.'))]"/>
<xsl:for-each select="Property[generate-id(.) =
generate-id(key('kPropertyByName',
concat(generate-id(..), '|', substring-before(@Name,'.')))[1])
] ">
<xsl:apply-templates select="." mode="parent"/>
</xsl:for-each>
</ObjectData>
</xsl:template>
<xsl:template match="Property[not(contains(@Name, '.'))]">
<xsl:element name="{@Name}">
<xsl:value-of select="@Value"/>
</xsl:element>
</xsl:template>
<xsl:template match="Property[(contains(@Name, '.'))]" mode="parent">
<xsl:element name="{substring-before(@Name,'.')}">
<xsl:apply-templates mode="child" select="../Property[
substring-before(current()/@Name,'.') =
substring-before(./@Name,'.')]"/>
</xsl:element>
</xsl:template>
<xsl:template match="Property[(contains(@Name, '.'))]" mode="child">
<xsl:element name="{substring-after(@Name,'.')}">
<xsl:value-of select="@Value"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Что дает мне следующий вывод - наличие (нежелательных) "неразделенных" C.*-элементов:
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<ObjectData>
<Id>001</Id>
<P>
<Id>Id P</Id>
<Description>Descr P</Description>
</P>
<A>
<Id>Id A</Id>
<Description>Descr A</Description>
</A>
<B>
<Id>Id B</Id>
<Description>Descr B</Description>
<C.Id>B.C.Id</C.Id>
<C.Description>B.C.Description</C.Description>
</B>
</ObjectData>
</Root>
Не то, что я ищу ... Любая помощь будет очень признательна снова!
Name="B.C.Id"
; вы использовали ранее созданный элемент B дляName="B.Id"
. Если вы не добавите еще несколько ограничений, эта проблема не будет четко определена. - person michael.hor257k   schedule 16.12.2014