#xslt #xpath
#xslt #xpath
Вопрос:
У меня есть следующий xml:
<vo class="GroupEntry" buildByAlias="true">
<objectClass name="groupOfNames"/>
<field name="commonName" nameLDAP="cn" type="String"/>
<field name="descriptione" nameLDAP="description" type="String"/>
<field name="member" nameLDAP="member" type="String[]"/>
</vo>
<update method="addMember" modificationMode="ADD_ATTRIBUTE">
<input>
<field name="member"/>
<field name="description"/>
</input>
</update>
Я использую XSLT для его преобразования, и мне нужно для каждого обновления получать поля в vo, которые соответствуют полю, определенному во входных данных. Это было бы что-то вроде этого:
<xsl:variable name="fields" select="vo/field" />
<xsl:for-each select="update">
<xsl:variable name='fieldsForInput' select = "$fields[@name]=input/fields[@name]"/>
<xsl:for-each select="$fieldsForInput">
<xsl:value-of select="@type"/> <xsl:value-of select="@name"/>
<xsl:for-each>
</xsl:for-each>
Но он ничего не нашел. Есть идеи?
Спасибо
JL
Комментарии:
1. Хороший вопрос, 1. Смотрите мой ответ для двух разных, полных, коротких и простых решений.
Ответ №1:
Из показанных фрагментов трудно помочь вам и понять, чего вы хотите. Однако ваш случай кажется идеальным для использования xsl:key
.
Например, если вы создаете ключ в начале преобразования следующим образом:
<xsl:key name="fields" match="vo/field" use="@name"/>
Вы можете использовать его внутри вашего шаблона соответствия следующим образом:
<xsl:for-each select="update/input">
<xsl:copy-of select="key('fields',current()/field/@name)"/>
</xsl:for-each>
В любом случае я бы не стал использовать xsl:foreach
. Но сложно предоставить вам полное решение, если вы предоставляете только фрагменты. Также неясно, хотите ли вы просто сопоставить или заменить field
.
Пример, показывающий, как получить поле name/type
для каждого update/input/field
.
XSLT 1.0 протестирован с Saxon 6.5.5
<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:key name="fields" match="vo/field" use="@name"/>
<xsl:template match="/root">
<xsl:apply-templates select="update"/>
</xsl:template>
<xsl:template match="update">
<xsl:value-of select="concat('-',@method,'amp;#xA;')"/>
<xsl:apply-templates select="input/field"/>
</xsl:template>
<xsl:template match="input/field">
<xsl:value-of select="concat('--',@name,' ',key('fields',@name)/@type,'amp;#xA;')"/>
</xsl:template>
</xsl:stylesheet>
Применяется на:
<root>
<vo class="GroupEntry" buildByAlias="true">
<objectClass name="groupOfNames"/>
<field name="commonName" nameLDAP="cn" type="String"/>
<field name="description" nameLDAP="description" type="String"/>
<field name="member" nameLDAP="member" type="String[]"/>
</vo>
<update method="addMember" modificationMode="ADD_ATTRIBUTE">
<input>
<field name="member"/>
<field name="description"/>
</input>
</update>
<update method="deleteMember" modificationMode="DELETE_ATTRIBUTE">
<input>
<field name="member"/>
<field name="description"/>
</input>
</update>
</root>
Выдает:
-addMember
--member String[]
--description String
-deleteMember
--member String[]
--description String
Комментарии:
1. Ну, я просто хочу, чтобы поле соответствовало. Дело в том, что мне нужно для каждого поля, определенного в обновлении / вводе, соответствующее поле в vo, поэтому мне не нужно определять тип и nameLDAP во входных данных, просто сделайте ссылку во входных данных и получите значения из vo.
2. Я просто отредактировал вопрос, чтобы уточнить, что именно мне нужно.
3. Если вы хотите уточнить, что вам нужно, вы должны предоставить XML-образец вашего вывода. Поскольку вы приняли ответ, я предполагаю, что теперь вы закончили. Ты?
4. Я расширил ответ чем-то, что может быть ближе к тому, что вам требуется.
5. Обратите внимание, что у вас была орфографическая ошибка в вашем
vo/field/@name
описании. Я изменил во входном документеdescriptione
наdescription
.
Ответ №2:
Два решения:
Решение1 (без ключей):
<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=
"vo/field[@name=../../update/*/*/@name]">
<xsl:value-of select="concat(@name,' ',@type,'amp;#xA;')"/>
</xsl:template>
</xsl:stylesheet>
При применении к предоставленному XML-документу (исправлено для придания правильной формы):
<t>
<vo class="GroupEntry" buildByAlias="true">
<objectClass name="groupOfNames"/>
<field name="commonName" nameLDAP="cn" type="String"/>
<field name="description" nameLDAP="description" type="String"/>
<field name="member" nameLDAP="member" type="String[]"/>
</vo>
<update method="addMember" modificationMode="ADD_ATTRIBUTE">
<input>
<field name="member"/>
<field name="description"/>
</input>
</update>
</t>
получен желаемый, правильный результат:
description String
member String[]
Решение2 (с использованием ключа):
<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:key name="kFieldByName" match="vo/field"
use="@name"/>
<xsl:template match="/*">
<xsl:apply-templates mode="selected" select=
"key('kFieldByName', update/*/*/@name)"/>
</xsl:template>
<xsl:template match="vo/field" mode="selected">
<xsl:value-of select="concat(@name,' ',@type,'amp;#xA;')"/>
</xsl:template>
</xsl:stylesheet>
при применении к тому же XML-документу (выше) получается тот же правильный результат:
description String
member String[]