2010-05-21 4 views
3

Рассмотрим следующий пример XML:XSLT добавление элементов на том же пути

<?xml version="1.0" encoding="ISO-8859-1"?> 
<catalog> 
    <cd> 
     <title>Empire Burlesque</title> 
     <artist> 
      <name>Bob</name> 
      <surname>Dylan</surname> 
     </artist> 
     <country>USA</country> 
     <company>Columbia</company> 
     <price>10.90</price> 
     <year>1985</year> 
    </cd> 
</catalog> 

Я хочу, чтобы добавить элементы в этом XML с помощью XSLT, чтобы получить следующий результат:

<?xml version="1.0" encoding="ISO-8859-1"?> 
<catalog> 
    <cd> 
     <title>Empire Burlesque</title> 
     <artist> 
      <name>Bob</name> 
      <surname>Dylan</surname> 
      <!-- NEW --> 
      <middlename>???</middlename> 
     </artist> 
     <country>USA</country> 
     <company>Columbia</company> 
     <price>10.90</price> 
     <year>1985</year> 
     <!-- NEW --> 
     <comment>great one</comment> 
    </cd> 
    <!-- NEW --> 
    <cd> 
     <title>Hide your heart</title> 
     <artist> 
      <name>Bonnie</name> 
      <surname>Tyler</surname> 
     </artist> 
     <country>UK</country> 
     <company>CBS Records</company> 
     <price>9.90</price> 
     <year>1988</year> 
    </cd> 
</catalog> 

Чтобы достичь этого, Я написал следующий XSLT:

<?xml version="1.0" encoding="ISO-8859-1"?> 

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:template name="injectXml"> 
    <xsl:param name="whatToInject"/> 
    <xsl:copy> 
     <xsl:copy-of select="node() | @*"/> 
     <xsl:copy-of select="$whatToInject"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="//catalog"> 
    <xsl:call-template name="injectXml"> 
     <xsl:with-param name="whatToInject"> 
     <cd> 
      <title>Hide your heart</title> 
      <artist> 
       <name>Bonnie</name> 
       <surname>Tyler</surname> 
      </artist> 
      <country>UK</country> 
      <company>CBS Records</company> 
      <price>9.90</price> 
      <year>1988</year> 
     </cd> 
     </xsl:with-param> 
    </xsl:call-template> 
    </xsl:template> 

    <xsl:template match="//cd[year=1985]"> 
    <xsl:call-template name="injectXml"> 
     <xsl:with-param name="whatToInject"> 
     <comment>great one</comment> 
     </xsl:with-param> 
    </xsl:call-template> 
    </xsl:template> 

    <xsl:template match="//cd[year=1985]/artist"> 
    <xsl:call-template name="injectXml"> 
     <xsl:with-param name="whatToInject"> 
     <middlename>???</middlename> 
     </xsl:with-param> 
    </xsl:call-template> 
    </xsl:template> 

</xsl:stylesheet> 

Почему он не работает? Как это сделать?

+0

Хороший вопрос (+1). См. Мой ответ для полного решения. –

ответ

1

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

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:my="my:my" 
exclude-result-prefixes="my xsl" 
> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<my:updates> 
    <update num="1"> 
    <comment>great one</comment> 
    </update> 
    <update num="2"> 
    <middlename>XXX</middlename> 
    </update> 
    <update num="3"> 
    <cd> 
     <title>Hide your heart</title> 
     <artist> 
      <name>Bonnie</name> 
      <surname>Tyler</surname> 
     </artist> 
     <country>UK</country> 
     <company>CBS Records</company> 
     <price>9.90</price> 
     <year>1988</year> 
    </cd> 
    </update> 
</my:updates> 

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

    <xsl:template match="catalog"> 
     <xsl:call-template name="inject"> 
     <xsl:with-param name="pUpdate" select="3"/> 
     </xsl:call-template> 
    </xsl:template> 

    <xsl:template match="cd[year=1985]"> 
     <xsl:call-template name="inject"> 
     <xsl:with-param name="pUpdate" select="1"/> 
     </xsl:call-template> 
    </xsl:template> 

    <xsl:template match="cd[year=1985]/artist"> 
     <xsl:call-template name="inject"> 
     <xsl:with-param name="pUpdate" select="2"/> 
     </xsl:call-template> 
    </xsl:template> 

    <xsl:template name="inject"> 
     <xsl:param name="pUpdate"/> 

     <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
     <xsl:apply-templates select= 
     "document('')/*/my:updates/*[@num=$pUpdate]/node()"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="*[ancestor::my:updates]"> 
     <xsl:element name="{name()}" namespace="{namespace-uri()}"> 
      <xsl:copy-of select= 
      "namespace::*[not(name()='my' or name()='xsl')]"/> 
      <xsl:apply-templates select="node()|@*"/> 
     </xsl:element> 
    </xsl:template> 
</xsl:stylesheet> 

при нанесении на условии Документ XML:

<catalog> 
    <cd> 
     <title>Empire Burlesque</title> 
     <artist> 
      <name>Bob</name> 
      <surname>Dylan</surname> 
     </artist> 
     <country>USA</country> 
     <company>Columbia</company> 
     <price>10.90</price> 
     <year>1985</year> 
    </cd> 
</catalog> 

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

<catalog> 
    <cd> 
     <title>Empire Burlesque</title> 
     <artist> 
     <name>Bob</name> 
     <surname>Dylan</surname> 
     <middlename>XXX</middlename> 
     </artist> 
     <country>USA</country> 
     <company>Columbia</company> 
     <price>10.90</price> 
     <year>1985</year> 
     <comment>great one</comment> 
    </cd> 
    <cd> 
     <title>Hide your heart</title> 
     <artist> 
     <name>Bonnie</name> 
     <surname>Tyler</surname> 
     </artist> 
     <country>UK</country> 
     <company>CBS Records</company> 
     <price>9.90</price> 
     <year>1988</year> 
    </cd> 
</catalog> 
+0

И я думал, что XSLT прост ... Спасибо за отличный ответ! – Stefan

+0

К сожалению, инструмент, который я использую, не поддерживает функцию ducument(). Есть ли обходной путь для этого (изменение XSLT)? – Stefan

+0

@Stefan: XSLT очень просто. Очистка пространства имен, которую я выполняю в этом решении, не требуется, когда обновления будут действительно в отдельном документе. –

0

Вы пробовали

матч = "// кд/год /[.= '1985']"

+0

Кажется, не работает для меня. Не могли бы вы объяснить, что он должен делать? – Stefan

Смежные вопросы