2016-10-07 1 views
1

У меня есть следующий источник XML документ:XSLT заменить элемент спички на основе значения дочернего узла

<UserDefinedFields> 
    <UserDefinedField> 
    <Name>ABC</Name> 
    <Value>123</Value> 
    </UserDefinedField> 
    <UserDefinedField> 
    <Name>XYZ</Name> 
    <Value>645q3245</Value> 
    </UserDefinedField> 
</UserDefinedFields> 

Я хочу, чтобы перезаписать соответствующие узлы из входного XML, если есть соответствие <Name> значения .. Так что в других слова, конечный результат слияния это:

<UserDefinedField> 
    <Name>XYZ</Name> 
    <Value>NEWVALUE!</Value> 
</UserDefinedField> 

... будет:

<UserDefinedFields> 
    <UserDefinedField> 
    <Name>ABC</Name> 
    <Value>123</Value> 
    </UserDefinedField> 
    <UserDefinedField> 
    <Name>XYZ</Name> 
    <Value>NEWVALUE!</Value> 
    </UserDefinedField> 
</UserDefinedFields> 

Что такое подходящая трансформация XSLT для достижения этой цели?

XSLT 2.0 или 1.0 ответы в порядке ... 2.0 предпочтительнее.

ответ

1

Вы можете сделать это с группировкой:

<xsl:for-each-group 
    select="$doc1//UserDefinedField, $doc2//UserDefinedField" 
    group-by="Name"> 
    <xsl:copy-of select="current-group()[last()]"/> 
</xsl:for-each-group> 
+0

Dr. Kay: Я понимаю, что в предлагаемом решении будут выводиться даже такие элементы '$ doc2 // UserDefinedField', которые не соответствуют элементу' $ doc1 // UserDefinedField'? Если это так, это не то, что хочет OP - он хочет вывести только такие элементы '$ doc2 // UserDefinedField', которые соответствуют (« переопределяют ») элементы в' $ doc1' –

+1

. Я не уверен, где ваше чтение требования OP берутся, но да, мое решение предполагает, что если есть запись в doc2, которая не соответствует записи в doc1, запись в doc2 будет добавлена ​​к выходу. Если это не так, вы можете настроить решение с помощью чего-то вроде if (current-group() [1]/(/) - $ doc1), затем ... ' –

+0

Dr. Kay, Re:" flag Я не уверен, где ваше чтение требований OP происходит от ".Это не просто мое чтение - это точно так же, как указано в вопросе: «Я хочу переписать соответствующие узлы из входного XML, если есть соответствующее значение ..» Обратите внимание на * if * ... –

0

Предполагая, что вы инструктаж процессора для обработки «начального» XML документа, и поставлять путь к «переопределяя» документ в качестве параметра, вы могли бы сделать :

XSLT 2,0

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

<xsl:param name="path-to-update">update.xml</xsl:param> 
<xsl:key name="fld" match="UserDefinedField" use="Name" /> 

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

<xsl:template match="Value"> 
    <xsl:variable name="update" select="key('fld', ../Name, document($path-to-update))" /> 
    <xsl:copy> 
     <xsl:value-of select="if ($update) then $update/Value else ."/> 
    </xsl:copy> 
</xsl:template> 

</xsl:stylesheet> 
0

Просто используйте этот шаблон для переопределения I Правило dentity:

<xsl:template match="UserDefinedField[key('kFieldByName', Name, $vDoc2)]/Value/text()"> 
    <xsl:value-of select="key('kFieldByName', ../../Name, $vDoc2)[1]"/> 
    </xsl:template> 

Здесь я предположить, что второй документ имеет элемент документа (верхний элемент) и может содержать по разной глубине много UserDefinedField элементов. Для удобства только второй документ встроен в преобразование - в реальном случае может использоваться функция doc(). Я также объявляю <xsl:key> для эффективного поиска нового значения с использованием значения дочернего элемента NameUserDefinedField во втором документе.

Вот полное преобразование:

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

<xsl:key name="kFieldByName" match="Value" use="../Name"/> 

<xsl:variable name="vDoc2"> 
    <patterns> 
    <UserDefinedField> 
     <Name>XYZ</Name> 
     <Value>NEWVALUE!</Value> 
     </UserDefinedField> 
    </patterns> 
</xsl:variable> 

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

    <xsl:template match="UserDefinedField[key('kFieldByName', Name, $vDoc2)]/Value/text()"> 
    <xsl:value-of select="key('kFieldByName', ../../Name, $vDoc2)[1]"/> 
    </xsl:template> 
</xsl:stylesheet> 

Когда это преобразование применяется на предоставленному документу XML:

<UserDefinedFields> 
    <UserDefinedField> 
    <Name>ABC</Name> 
    <Value>123</Value> 
    </UserDefinedField> 
    <UserDefinedField> 
    <Name>XYZ</Name> 
    <Value>645q3245</Value> 
    </UserDefinedField> 
</UserDefinedFields> 

разыскиваемый, правильный результат производства:

<UserDefinedFields> 
    <UserDefinedField> 
     <Name>ABC</Name> 
     <Value>123</Value> 
    </UserDefinedField> 
    <UserDefinedField> 
     <Name>XYZ</Name> 
     <Value>NEWVALUE!</Value> 
    </UserDefinedField> 
</UserDefinedFields>