XSLT 1.0 копирует и удаляет узел

Мне нужно скопировать узел (Set_Item/ForwarderReferenceNumber) в случае многократного повтора, а затем удалить узел «Set_Item», из которого мы взяли значение.

Чтобы найти тот же Set_Item (но другой ForwarderReferenceNumer), нам нужно использовать «Set_Item/GTIN»). -> Итак, в моем примере мы видим, что «GTIN» «LineNum» 2 и 7 идентичен (555), и теперь нам нужно скопировать «Set_Item/ForwarderReferenceNumber» из строки 7 ниже «Set_Item/ForwarderReferenceNumber» строки. 2, а затем удалите весь узел «Set_Item» с помощью «LineNum» 7.

пример XML:

<OSTRPT>
  <LineInformation>  
    <Set_Item>
      <LineNum>2</LineNum>
      <GTIN>555</GTIN>      
      <Quantity>1.00</Quantity>
      <MeasureUnit>PCE</MeasureUnit>
      <DeliveryDate>2024-03-13</DeliveryDate>
      <Status>24</Status>     
      <ForwarderReferenceNumber>666</ForwarderReferenceNumber>  
      <Date>2</Date>          
    </Set_Item>
    <Set_Item>
      <LineNum>7</LineNum>
      <GTIN>555</GTIN>     
      <Quantity>1.00</Quantity>
      <MeasureUnit>PCE</MeasureUnit>
      <DeliveryDate>2024-03-13</DeliveryDate>
      <Status>24</Status>      
      <ForwarderReferenceNumber>777</ForwarderReferenceNumber> 
      <Date>3</Date>          
    </Set_Item>
  </LineInformation>
</OSTRPT>

Это должен быть правильный вывод:

<OSTRPT>
  <LineInformation>  
    <Set_Item>
      <LineNum>2</LineNum>
      <GTIN>555</GTIN>      
      <Quantity>1.00</Quantity>
      <MeasureUnit>PCE</MeasureUnit>
      <DeliveryDate>2024-03-13</DeliveryDate>
      <Status>24</Status>     
      <ForwarderReferenceNumber>666</ForwarderReferenceNumber>
      <ForwarderReferenceNumber>777</ForwarderReferenceNumber> 
      <Date>2</Date>      
    </Set_Item>
  </LineInformation>
</OSTRPT>

Вот мой текущий xslt. (Но решения для этого случая нет)

<xsl:stylesheet version = "1.0" 
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" 
xmlns:exsl = "http://exslt.org/common" extension-element-prefixes = "exsl">

 <xsl:output method = "xml" indent = "yes" encoding = "UTF-8"/>
 
  <xsl:strip-space elements = "*" />

    <xsl:template match = "/">   
        <xsl:choose>
            <xsl:when test = "//LineInformation[not(Item)] and //LineInformation[not(Set_Item)]"></xsl:when>
            <xsl:when test = "not(//Set_Item) and not(//Item)"></xsl:when>
                <xsl:otherwise> <xsl:apply-templates select = "@* | node()"/></xsl:otherwise>
        </xsl:choose>
    </xsl:template>

  <xsl:key name = "header_text" match = "HeaderText" use = "Text"/>
  <xsl:key name = "line_text" match = "LineText" use = "concat(../LineNum, '|', Text)"/>
  <xsl:key name = "allowance_charge_header" match = "AllowanceOrCharge_Header" use = "concat(Code, '|', Amount)"/>
  <xsl:key name = "allowance_charge_line" match = "AllowanceOrCharge_Line" use = "concat(../LineNum, '|', Code, '|', Amount)"/>
  <xsl:key name = "packing_slip" match = "ItemDeliveryInformation" use = "concat(../LineNum, '|', PackingSlipId, '|', DeliveryDate, '|', DeliveredQuantity)"/>
  <xsl:key name = "item" match = "Item" use = "concat(LineNum, '|', GTIN, '|', SupplierArticleNumber, '|', Quantity)"/>
  <xsl:key name = "set_item" match = "Set_Item" use = "concat(LineNum, '|', GTIN, '|', SupplierArticleNumber, '|', ForwarderReferenceNumber)"/>
  <xsl:key name = "WeightAndVolume" match = "WeightAndVolume" use = "Weight_RecId"/>
  <xsl:key name = "ContainerInformation" match = "ContainerInformation" use = "SSCC_RecId"/>
  <xsl:key name = "ContainerInformation_Set_Item" match = "ContainerInformation_Set_Item" use = "SSCC"/>

  <!-- Identity-Template für die nicht explizit benannten Elemente -->
  <xsl:template match = "@* | node()">
    <xsl:copy>
      <xsl:apply-templates select = "@* | node()"/>
    </xsl:copy>
  </xsl:template>

    <xsl:template match = "//Forwarder/Code[//Forwarder/Country = 'DE' and //Forwarder/Name[contains(., 'GLS')]]">
        <Code>5</Code>       
    </xsl:template>
  
  <!-- Entfernt alles nach und inkl. "_" -->
  <xsl:template match = "GLN[contains(., '_')]">
    <GLN><xsl:value-of select = "substring-before(., '_')"/></GLN>
  </xsl:template>
  
  <!-- Entfernt alles nach und inkl. "_" -->
  <xsl:template match = "Recipient[contains(., '_')]">
    <Recipient><xsl:value-of select = "substring-before(., '_')"/></Recipient>
  </xsl:template>
  
      <xsl:template match = "ItemDeliveryInformation_Set_Item">        
        <xsl:element name = "ItemDeliveryInformation">       
    <!--copy all other nodes-->
    <xsl:apply-templates select = "@* | node()"/>
        </xsl:element>
    </xsl:template>

  <xsl:template match = "Set_Item">        
     <xsl:element name = "Item">
    <!--copy all other nodes-->
    <xsl:apply-templates select = "@* | node()"/>
        </xsl:element>
    </xsl:template>

  <xsl:template match = "RFF_Line_Set_Item">        
     <xsl:element name = "RFF_Line">
    <!--copy all other nodes-->
    <xsl:apply-templates select = "@* | node()"/>
        </xsl:element>
    </xsl:template>
    
      <xsl:template match = "ContainerInformation_Set_Item">        
     <xsl:element name = "ContainerInformation">
    <!--copy all other nodes-->
    <xsl:apply-templates select = "@* | node()"/>
        </xsl:element>
    </xsl:template>

  <!-- Differenz zwischen bestellter und gelieferter Menge -->
  <xsl:template match = "Item/ItemDeliveryInformation[. != '']">
    <xsl:copy>
    <!--copy all other nodes-->
      <xsl:apply-templates select = "@* | node()"/>
    <QtyDifference>
        <xsl:value-of select = "format-number((./DeliveredQuantity - ../Ordered), '#0.00')"/>
    </QtyDifference>  
    </xsl:copy>
  </xsl:template> 

  <!-- das aufzurufende Template: OrderResponseReference Teil 1-->
<xsl:template name = "last-substring-after">
  <xsl:param name = "search"/>
  <xsl:param name = "string"/>
  <xsl:variable name = "result" select = "substring-after($string, $search)"/>
    <xsl:choose>
        <xsl:when test = "contains($result, $search)">
            <xsl:call-template name = "last-substring-after">
            <xsl:with-param name = "search" select = "$search"/>
            <xsl:with-param name = "string" select = "$result"/>
      </xsl:call-template>
        </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select = "$result"/>
            </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<!-- das aufzurufende Template: OrderResponseReference Teil 2-->
  <xsl:template match = "OrderResponseReference[contains (., '/')]">
    <OrderResponseReference>    
        <xsl:call-template name = "last-substring-after">
        <xsl:with-param name = "search" select = "'/'"/>
        <xsl:with-param name = "string" select = "."/>
    </xsl:call-template>
    </OrderResponseReference>
  </xsl:template>
  
  <xsl:template match = "OrderResponseReference[not(contains (., '/'))]">
    <OrderResponseReference><xsl:value-of select = "." /></OrderResponseReference>    
  </xsl:template>    

  <xsl:template match = "HeaderText[generate-id() != generate-id(key('header_text', Text)[1])]" />
  <xsl:template match = "LineText[generate-id() != generate-id(key('line_text', concat(../LineNum, '|', Text))[1])]" />
  <xsl:template match = "AllowanceOrCharge_Header[generate-id() != generate-id(key('allowance_charge_header', concat(Code, '|', Amount))[1])]" />
  <xsl:template match = "AllowanceOrCharge_Line[generate-id() != generate-id(key('allowance_charge_line', concat(../LineNum, '|', Code, '|', Amount))[1])]" />
  <xsl:template match = "ItemDeliveryInformation[generate-id() != generate-id(key('packing_slip', concat(../LineNum, '|', PackingSlipId, '|', DeliveryDate, '|', DeliveredQuantity))[1])]" />
  <xsl:template match = "Item[generate-id() != generate-id(key('item', concat(LineNum, '|', GTIN, '|', SupplierArticleNumber, '|', Quantity))[1])]" />
  <xsl:template match = "Set_Item[generate-id() != generate-id(key('set_item', concat(LineNum, '|', GTIN, '|', SupplierArticleNumber, '|', ForwarderReferenceNumber))[1])]" />
  <xsl:template match = "WeightAndVolume[generate-id() != generate-id(key('WeightAndVolume', Weight_RecId)[1])]" />
  <xsl:template match = "ContainerInformation[generate-id() != generate-id(key('ContainerInformation', SSCC_RecId)[1])]" />
  <xsl:template match = "ContainerInformation_Set_Item[generate-id() != generate-id(key('ContainerInformation_Set_Item', SSCC)[1])]" />

  <!-- Delete 0 at PackagingQty -->
  <xsl:template match = "PackagingUnit[PackagingQty = '0.00' or AllowanceOrChargeAmount = '0']"/>

  <!-- Delete 0 at ContainerInformation/SSCC_RecId -->
  <xsl:template match = "ContainerInformation/SSCC_RecId"/>
  
    <!-- Delete 0 at ContainerInformation/SSCC_RecId -->
  <xsl:template match = "ContainerInformation_Set_Item/SSCC_RecId"/>

  <!-- Delete 0 at WeightAndVolume/Weight_RecId -->
  <xsl:template match = "WeightAndVolume/Weight_RecId"/>
  
<!-- delete empty nodes -->
 <xsl:template match = "node()|@*">
     <xsl:copy>
       <xsl:apply-templates select = "node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match = "*[not(@*|*|comment()|processing-instruction()) and normalize-space()='']"/>

</xsl:stylesheet>

Вот пример с повторяющимися строками:

<?xml version = "1.0" encoding = "utf-8" standalone = "yes"?>
<OSTRPT>
  <LineInformation>
    <Set_Item>
      <LineNum>4</LineNum>
      <GTIN>4251431238524</GTIN>
      <SupplierArticleNumber>95003G4103VS</SupplierArticleNumber>
      <Quantity>1.00</Quantity>
      <MeasureUnit>PCE</MeasureUnit>
      <DeliveryDate>2024-03-13</DeliveryDate>
      <Status>24</Status>
      <StatusDescription>Ware versendet</StatusDescription>
      <StatusChangeDate>2024-04-04T14:47:56</StatusChangeDate>
      <ForwarderReferenceNumber>090028350002745490</ForwarderReferenceNumber>
      <ReferenceDate>2024-04-04T14:47:56</ReferenceDate>
    </Set_Item>   
    <Set_Item>
      <LineNum>4</LineNum>
      <GTIN>4251431238524</GTIN>
      <SupplierArticleNumber>95003G4103VS</SupplierArticleNumber>
      <Quantity>1.00</Quantity>
      <MeasureUnit>PCE</MeasureUnit>
      <DeliveryDate>2024-03-13</DeliveryDate>
      <Status>24</Status>
      <StatusDescription>Ware versendet</StatusDescription>
      <StatusChangeDate>2024-04-04T14:48:06</StatusChangeDate>
      <ForwarderReferenceNumber>090028350002745513</ForwarderReferenceNumber>
      <ReferenceDate>2024-04-04T14:47:56</ReferenceDate>
    </Set_Item>
    <Set_Item>
      <LineNum>4</LineNum>
      <GTIN>4251431238524</GTIN>
      <SupplierArticleNumber>95003G4103VS</SupplierArticleNumber>
      <Quantity>1.00</Quantity>
      <MeasureUnit>PCE</MeasureUnit>
      <DeliveryDate>2024-03-13</DeliveryDate>
      <Status>24</Status>
      <StatusDescription>Ware versendet</StatusDescription>
      <StatusChangeDate>2024-04-04T14:48:06</StatusChangeDate>
      <ForwarderReferenceNumber>090028350002745513</ForwarderReferenceNumber>
      <ReferenceDate>2024-04-04T14:47:56</ReferenceDate>
    </Set_Item>    
  </LineInformation>
</OSTRPT>

Спасибо!

с наилучшими пожеланиями Джулиан

Я не смог уследить за вашим объяснением. Возможно ли, что это проблема с группировкой?

michael.hor257k 10.04.2024 08:33

Я думаю, это тоже может мне помочь. В моем xml я получаю один и тот же Set_Item дважды (если GTIN один и тот же на разных узлах - это означает, что это одна и та же статья). Но мне это нужно только один раз. Но значение разных ForwarderReferenceNumber не идентично в обеих строках, где GTIN идентичен. Вот почему я сначала скопирую его, прежде чем удалять повторяющиеся строки.

juls_pro_37 10.04.2024 08:56

Рассмотрите возможность сокращения примера до минимума, необходимого для демонстрации проблемы — см.: минимальный воспроизводимый пример .

michael.hor257k 10.04.2024 09:44

сделанный. Я подумал, что лучше добавить еще несколько узлов, вы можете видеть, что могут быть дополнительные сегменты.

juls_pro_37 10.04.2024 10:09

Это действительно проблема с группировкой, найдите «мюнхийский метод группировки xslt».

plykkegaard 10.04.2024 10:43

да, но, пожалуйста, мне нужна помощь, чтобы создать его правильно.

juls_pro_37 10.04.2024 12:51
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Используйте ключ и обрабатывайте все ForwarderReferenceNumbers в «группе», образованной этим ключом:

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

<xsl:key name = "group" match = "Set_Item" use = "GTIN"/>

<xsl:template match = "Set_Item[not(generate-id() = generate-id(key('group', GTIN)[1]))]"/>

<xsl:template match = "ForwarderReferenceNumber">
  <xsl:copy-of select = ". | key('group', ../GTIN)/ForwarderReferenceNumber"/>
</xsl:template>

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

</xsl:stylesheet>`;

var domParser = new DOMParser();

var xsltProcessor = new XSLTProcessor();

xsltProcessor.importStylesheet(domParser.parseFromString(xslt, 'application/xml'));

var resultDoc = xsltProcessor.transformToDocument(domParser.parseFromString(document.getElementById('xml').text, 'application/xml'));

console.info(resultDoc);

console.info(new XMLSerializer().serializeToString(resultDoc));
<script id = "xml" type = "application/xml">
<OSTRPT>
  <LineInformation>  
    <Set_Item>
      <LineNum>2</LineNum>
      <GTIN>555</GTIN>      
      <Quantity>1.00</Quantity>
      <MeasureUnit>PCE</MeasureUnit>
      <DeliveryDate>2024-03-13</DeliveryDate>
      <Status>24</Status>     
      <ForwarderReferenceNumber>666</ForwarderReferenceNumber>  
      <Date>2</Date>          
    </Set_Item>
    <Set_Item>
      <LineNum>7</LineNum>
      <GTIN>555</GTIN>     
      <Quantity>1.00</Quantity>
      <MeasureUnit>PCE</MeasureUnit>
      <DeliveryDate>2024-03-13</DeliveryDate>
      <Status>24</Status>      
      <ForwarderReferenceNumber>777</ForwarderReferenceNumber> 
      <Date>3</Date>          
    </Set_Item>
  </LineInformation>
</OSTRPT>
</script>

Если вам также необходимо удалить дубликаты из ForwarderReferenceNumber, используйте второй ключ:

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

<xsl:key name = "gtin-group" match = "Set_Item" use = "GTIN"/>

<xsl:key name = "gtin-ref-group" match = "Set_Item" use = "concat(GTIN, '|', ForwarderReferenceNumber)"/>

<xsl:template match = "Set_Item[not(generate-id() = generate-id(key('gtin-group', GTIN)[1]))]"/>

<xsl:template match = "ForwarderReferenceNumber">
  <xsl:copy-of select = ". | key('gtin-group', ../GTIN)[generate-id() = generate-id(key('gtin-ref-group', concat(GTIN, '|', ForwarderReferenceNumber))[1])]/ForwarderReferenceNumber"/>
</xsl:template>

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

</xsl:stylesheet>`;

var domParser = new DOMParser();

var xsltProcessor = new XSLTProcessor();

xsltProcessor.importStylesheet(domParser.parseFromString(xslt, 'application/xml'));

var resultDoc = xsltProcessor.transformToDocument(domParser.parseFromString(document.getElementById('xml').text, 'application/xml'));

//console.info(resultDoc);

console.info(new XMLSerializer().serializeToString(resultDoc));
<script id = "xml" type = "application/xml">
<OSTRPT>
  <LineInformation>  
    <Set_Item>
      <LineNum>2</LineNum>
      <GTIN>555</GTIN>      
      <Quantity>1.00</Quantity>
      <MeasureUnit>PCE</MeasureUnit>
      <DeliveryDate>2024-03-13</DeliveryDate>
      <Status>24</Status>     
      <ForwarderReferenceNumber>666</ForwarderReferenceNumber>  
      <Date>2</Date>          
    </Set_Item>
    <Set_Item>
      <LineNum>7</LineNum>
      <GTIN>555</GTIN>     
      <Quantity>1.00</Quantity>
      <MeasureUnit>PCE</MeasureUnit>
      <DeliveryDate>2024-03-13</DeliveryDate>
      <Status>24</Status>      
      <ForwarderReferenceNumber>777</ForwarderReferenceNumber> 
      <Date>3</Date>          
    </Set_Item>
    <Set_Item>
      <LineNum>7</LineNum>
      <GTIN>555</GTIN>     
      <Quantity>1.00</Quantity>
      <MeasureUnit>PCE</MeasureUnit>
      <DeliveryDate>2024-03-13</DeliveryDate>
      <Status>24</Status>      
      <ForwarderReferenceNumber>777</ForwarderReferenceNumber> 
      <Date>3</Date>          
    </Set_Item>
  </LineInformation>
</OSTRPT>
</script>

спасибо большое, в целом выглядит хорошо. но если узел «Set_Item» умножается на тот же «ForwarderReferenceNumber» в XML, то я получаю умноженное значение «ForwarderReferenceNumber» с тем же содержимым. Мне нужен контент только один раз. Надеюсь, вы понимаете мой вопрос. Я добавляю пример в свой вопрос выше.

juls_pro_37 10.04.2024 15:59

Другие вопросы по теме