Как изменить значения атрибутов элемента с помощью подстроки в XML с помощью XLS в нескольких узлах

#xml #xslt #code-snippets

Вопрос:

Я пытаюсь изменить значения категории «имя» во всех узлах в этом образце XML

 <?xml version="1.0" encoding="utf-8"?>
<offer xmlns:iof="********" xmlns:iaiext="******" file_format="IOF" generated="***" expires="***" version="3.0" extensions="yes">
  <products currency="EUR" iof_translation_generated="no" language="eng">
    <product id="170" currency="EUR" code_on_card="******" producer_code_standard="GTIN13" type="regular" vat="23.0" site="1">
      <producer id="1404978613" name="Test"/>
      <category id="1214554589" name="Cell phone screwdrivers"/>
      <category_idosell id="2898" path="Hardware amp;> Tools"/>
      <unit id="0" name="pc."/>
      <warranty id="2" type="seller" period="12" name="Cell phone accessories"/>
      <price gross="1.1" net="0.9"/>
    </product>
    <product id="411" currency="EUR" code_on_card="******" producer_code_standard="OTHER" type="regular" vat="23.0" site="1">
      <producer id="1404978613" name="Test"/>
      <category id="1214554594" name="Service Tools"/>
      <category_idosell id="2898" path="Hardware amp;> Tools"/>
      <unit id="0" name="pc."/>
      <warranty id="1" type="seller" period="6" name="Cell phone spare parts"/>
      <price gross="10.84" net="8.82"/>
    </product>
</products>
</offer>
 

с помощью этого фрагмента XSL:

 <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">
  
<xsl:template match="@*|node()">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
</xsl:template>
<xsl:template match="category/@name">
   
        <xsl:element name="category">
            <xsl:attribute name="name">
                <xsl:value-of select="substring-before(//category_idosell[1]/@path, ' amp;> ')"/>
                <xsl:value-of select="'///'"/>
                <xsl:value-of select="substring-after(//category_idosell[1]/@path, ' amp;> ')"/>
                <xsl:value-of select="'///'"/>
                <xsl:value-of select="//category[1]/@name"/>
            </xsl:attribute>
        </xsl:element>
    </xsl:template>
    
</xsl:stylesheet>
 

Он работает, когда я использую его в одном узле, но когда у меня больше узлов (продуктов), он выдает мне эту ошибку:

 A sequence of more than one item is not allowed as the first argument of fn:substring-before() ("Hardware > Tools", "Hardware > Tools")
 

может ли кто-нибудь помочь мне в том, чего мне не хватает и как это сделать?
Заранее спасибо

Комментарии:

1.Не имеет отношения к вашему вопросу, но ваш шаблон соответствует name атрибуту и заменяет его category элементом, имеющим свой собственный name атрибут. Я сомневаюсь, что это то, чего ты действительно хочешь, — даже несмотря на то, что ты говоришь, что «это работает».

Ответ №1:

Ваш пример немного двусмыслен, потому что оба продукта имеют одинаковое значение category_idosell/@path . АФАИКТ, ты хочешь сделать просто:

 <xsl:template match="category/@name">
    <xsl:attribute name="name">
        <xsl:value-of select="substring-before(../../category_idosell/@path, ' amp;> ')"/>
        <xsl:text>///</xsl:text>
        <xsl:value-of select="substring-after(../../category_idosell/@path, ' amp;> ')"/>
        <xsl:text>///</xsl:text>
        <xsl:value-of select="."/>
    </xsl:attribute>
</xsl:template>
 

или еще проще:

 <xsl:template match="category/@name">
    <xsl:attribute name="name">
        <xsl:value-of select="replace(../../category_idosell/@path, ' amp;> ', '///')"/>
        <xsl:text>///</xsl:text>
        <xsl:value-of select="."/>
    </xsl:attribute>
</xsl:template>
 

Ответ №2:

Вы не сказали, какой вывод вам нужен, поэтому ваш код трудно исправить.

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

 (//category_idosell)[1]
 

Если вы хотите получить значение от текущего продукта, используйте

 ../category_idosell
 

Комментарии:

1. вывод, который я хочу, чтобы в каждом продукте категория была такой: <название категории=»Оборудование//Инструменты//Отвертки для мобильных телефонов»/><название категории=»Оборудование//Инструменты//Отвертки для мобильных телефонов»/></категория> </категория><название категории=»Оборудование//Инструменты//Сервисные инструменты»/><название категории=»Оборудование//Инструменты//Сервисные инструменты»/></категория> но со всей структурой XML просто пересмотрите категорию

Ответ №3:

Внутри шаблона, например xsl:template match="category/@name" , изменяется узел контекста, и в вашем случае это name узел атрибута, поэтому вы хотите писать выражения путей относительно этого узла, например ../../category_idosell[1]/@path , а не абсолютные пути, начиная с // поиска по всему документу. Основываясь на этом и отличном комментарии о том, что ваш код пытается создать элемент, в то время как вы, похоже, просто хотите изменить значение узла атрибута, я думаю, вам нужно что-то вроде

   <xsl:template match="category/@name">
      <xsl:attribute name="{name()}"
        select="concat(substring-before(../../category_idosell[1]/@path, ' amp;> '), '///',substring-after(../../category_idosell[1]/@path, ' amp;> '),'///', .)"/>
  </xsl:template>