2013-02-14 3 views
0

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

<?xml version="1.0" encoding="UTF-8"?> 
<Items> 
<Item> 
    <ITEM_CODE>ITEM_CODE</ITEM_CODE> 
    <ITEM_NAME>ITEM_NAME</ITEM_NAME> 
    <ITEM_ALTERNATE_NAME>ITEM_ALTERNATE_NAME</ITEM_ALTERNATE_NAME> 
    <ITEM_CATEGORY_CODE>ITEM_CATEGORY_CODE</ITEM_CATEGORY_CODE> 
</Item> 
<Item> 
    <ITEM_CODE>15031</ITEM_CODE> 
    <ITEM_NAME>Outer Carton</ITEM_NAME> 
    <ITEM_ALTERNATE_NAME/> 
    <ITEM_CATEGORY_CODE>52401</ITEM_CATEGORY_CODE> 
</Item> 
<Item> 
    <ITEM_CODE>150529</ITEM_CODE> 
    <ITEM_NAME>Outer Carton</ITEM_NAME> 
    <ITEM_ALTERNATE_NAME/> 
    <ITEM_CATEGORY_CODE>52401</ITEM_CATEGORY_CODE> 
</Item> 
<Item> 
    <ITEM_CODE>150999</ITEM_CODE> 
    <ITEM_NAME>Outer Carton</ITEM_NAME> 
    <ITEM_ALTERNATE_NAME/> 
    <ITEM_CATEGORY_CODE>52401</ITEM_CATEGORY_CODE> 
</Item> 
<Item> 
    <ITEM_CODE>150988</ITEM_CODE> 
    <ITEM_NAME>test</ITEM_NAME> 
    <ITEM_ALTERNATE_NAME/> 
    <ITEM_CATEGORY_CODE>52401</ITEM_CATEGORY_CODE> 
</Item> 
</Items> 

Если <ITEM_NAME> элементов имеют дублирующие содержания те должны быть переименованным с суффиксом, например, значение счетчика. Я придумал этот XSLT:

<?xml version="1.0" encoding="UTF-8"?> 

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

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

<xsl:key name="keyItemName" match="Item" use="concat(ITEM_CODE , '|', ITEM_NAME)"/> 

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

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

<xsl:template match="ITEM_NAME"> 

    <xsl:for-each select="parent::Item[generate-id()=generate-id(key('keyItemName',concat(ITEM_CODE , '|', ITEM_NAME))[1])]"> 
     <xsl:variable name="number"> 
      <xsl:number/> 
     </xsl:variable> 
     <ITEM_NAME> 
      <xsl:value-of select="concat(ITEM_NAME,'-',$number)"/> 
     </ITEM_NAME> 
    </xsl:for-each> 
</xsl:template> 

</xsl:stylesheet> 

Это дает мне этот выход:

<?xml version="1.0" encoding="UTF-8"?> 
<Items> 
<Item> 
    <ITEM_CODE>ITEM_CODE</ITEM_CODE> 
    <ITEM_NAME>ITEM_NAME-1</ITEM_NAME> 
    <ITEM_ALTERNATE_NAME>ITEM_ALTERNATE_NAME</ITEM_ALTERNATE_NAME> 
    <ITEM_CATEGORY_CODE>ITEM_CATEGORY_CODE</ITEM_CATEGORY_CODE> 
</Item> 
<Item> 
    <ITEM_CODE>15031</ITEM_CODE> 
    <ITEM_NAME>Outer Carton-2</ITEM_NAME> 
    <ITEM_ALTERNATE_NAME/> 
    <ITEM_CATEGORY_CODE>52401</ITEM_CATEGORY_CODE> 
</Item> 
<Item> 
    <ITEM_CODE>150529</ITEM_CODE> 
    <ITEM_NAME>Outer Carton-3</ITEM_NAME> 
    <ITEM_ALTERNATE_NAME/> 
    <ITEM_CATEGORY_CODE>52401</ITEM_CATEGORY_CODE> 
</Item> 
<Item> 
    <ITEM_CODE>150999</ITEM_CODE> 
    <ITEM_NAME>Outer Carton-4</ITEM_NAME> 
    <ITEM_ALTERNATE_NAME/> 
    <ITEM_CATEGORY_CODE>52401</ITEM_CATEGORY_CODE> 
</Item> 
<Item> 
    <ITEM_CODE>150988</ITEM_CODE> 
    <ITEM_NAME>test-5</ITEM_NAME> 
    <ITEM_ALTERNATE_NAME/> 
    <ITEM_CATEGORY_CODE>52401</ITEM_CATEGORY_CODE> 
</Item> 
</Items> 

Но я надеюсь, этот вывод:

<?xml version="1.0" encoding="UTF-8"?> 
<Items> 
<Item> 
    <ITEM_CODE>ITEM_CODE</ITEM_CODE> 
    <ITEM_NAME>ITEM_NAME</ITEM_NAME> 
    <ITEM_ALTERNATE_NAME>ITEM_ALTERNATE_NAME</ITEM_ALTERNATE_NAME> 
    <ITEM_CATEGORY_CODE>ITEM_CATEGORY_CODE</ITEM_CATEGORY_CODE> 
</Item> 
<Item> 
    <ITEM_CODE>15031</ITEM_CODE> 
    <ITEM_NAME>Outer Carton-2</ITEM_NAME> 
    <ITEM_ALTERNATE_NAME/> 
    <ITEM_CATEGORY_CODE>52401</ITEM_CATEGORY_CODE> 
</Item> 
<Item> 
    <ITEM_CODE>150529</ITEM_CODE> 
    <ITEM_NAME>Outer Carton-3</ITEM_NAME> 
    <ITEM_ALTERNATE_NAME/> 
    <ITEM_CATEGORY_CODE>52401</ITEM_CATEGORY_CODE> 
</Item> 
<Item> 
    <ITEM_CODE>150999</ITEM_CODE> 
    <ITEM_NAME>Outer Carton-4</ITEM_NAME> 
    <ITEM_ALTERNATE_NAME/> 
    <ITEM_CATEGORY_CODE>52401</ITEM_CATEGORY_CODE> 
</Item> 
<Item> 
    <ITEM_CODE>150988</ITEM_CODE> 
    <ITEM_NAME>test</ITEM_NAME> 
    <ITEM_ALTERNATE_NAME/> 
    <ITEM_CATEGORY_CODE>52401</ITEM_CATEGORY_CODE> 
</Item> 
</Items> 

В последних <Item>ITEM_NAME не должны быть переименованы потому что он не называется «Внешняя упаковка». Также в первом элементе <Item> переименование не должно происходить.

Я близок к решению, но я просто не могу обойти его. Может кто-то помочь - спасибо большое!

С наилучшими пожеланиями, Питер

ответ

0

вы текущий ключ, кажется, присоединиться ITEM_NAME и ITEM_CODE, но это выглядит, как вы только хотите ITEM_NAME здесь

<xsl:key name="keyItemName" match="ITEM_NAME" use="."/> 

Также похоже, что нумерация для суффикса должна основываться на позиции родителя Элемент. Одним из способов достижения этой цели является иметь шаблон для соответствия элемента элемента, а затем передать номер в качестве параметра для последующих шаблонов mathching

<xsl:template match="Item"> 
    <Item> 
     <xsl:apply-templates select="@*|node()"> 
      <xsl:with-param name="number"> 
      <xsl:number/> 
     </xsl:with-param> 
     </xsl:apply-templates> 
    </Item> 
</xsl:template> 

Тогда вам нужен шаблон, чтобы соответствовать ITEM_NAME элементов для которого происходит дублирование. Это может быть сделано просто путем проверки есть по крайней мере, второй элемент, определенный в группе для ключа:

<xsl:template match="ITEM_NAME[key('keyItemName', .)[2]]"> 
    <xsl:param name="number"/> 

Затем, вы можете просто вывести элемент с суффиксом.

Вот полный XSLT

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

    <xsl:key name="keyItemName" match="ITEM_NAME" use="."/> 

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

    <xsl:template match="Item"> 
     <Item> 
     <xsl:apply-templates select="@*|node()"> 
      <xsl:with-param name="number"> 
       <xsl:number/> 
      </xsl:with-param> 
     </xsl:apply-templates> 
     </Item> 
    </xsl:template> 

    <xsl:template match="ITEM_NAME[key('keyItemName', .)[2]]"> 
     <xsl:param name="number"/> 
     <ITEM_NAME> 
     <xsl:value-of select="concat(.,'-',$number)"/> 
     </ITEM_NAME> 
    </xsl:template> 
</xsl:stylesheet> 

Применительно к вашему XML, следующий выход

<Items> 
    <Item> 
     <ITEM_CODE>ITEM_CODE</ITEM_CODE> 
     <ITEM_NAME>ITEM_NAME</ITEM_NAME> 
     <ITEM_ALTERNATE_NAME>ITEM_ALTERNATE_NAME</ITEM_ALTERNATE_NAME> 
     <ITEM_CATEGORY_CODE>ITEM_CATEGORY_CODE</ITEM_CATEGORY_CODE> 
    </Item> 
    <Item> 
     <ITEM_CODE>15031</ITEM_CODE> 
     <ITEM_NAME>Outer Carton-2</ITEM_NAME> 
     <ITEM_ALTERNATE_NAME/> 
     <ITEM_CATEGORY_CODE>52401</ITEM_CATEGORY_CODE> 
    </Item> 
    <Item> 
     <ITEM_CODE>150529</ITEM_CODE> 
     <ITEM_NAME>Outer Carton-3</ITEM_NAME> 
     <ITEM_ALTERNATE_NAME/> 
     <ITEM_CATEGORY_CODE>52401</ITEM_CATEGORY_CODE> 
    </Item> 
    <Item> 
     <ITEM_CODE>150999</ITEM_CODE> 
     <ITEM_NAME>Outer Carton-4</ITEM_NAME> 
     <ITEM_ALTERNATE_NAME/> 
     <ITEM_CATEGORY_CODE>52401</ITEM_CATEGORY_CODE> 
    </Item> 
    <Item> 
     <ITEM_CODE>150988</ITEM_CODE> 
     <ITEM_NAME>test</ITEM_NAME> 
     <ITEM_ALTERNATE_NAME/> 
     <ITEM_CATEGORY_CODE>52401</ITEM_CATEGORY_CODE> 
    </Item> 
</Items> 
+0

Привет, Тим, спасибо за это элегантное и очень эффективное решение. Поскольку мой фактический XML является огромным файлом, ваше решение лучше соответствует производительности. Прохождение позиции очень аккуратно - я должен проанализировать все это во второй половине дня, когда у меня есть время. Большое спасибо, Питер – Peter

1

Использование preceding:: или preceding-sibling:: считать предыдущие экземпляры не очень эффективен в вычислительном отношении, но я не вижу, как вокруг него здесь. Подход ниже имеет то преимущество, что она считает только предшествующие случаи, когда после проверки (с помощью ключа, который очень быстро), что существует и другие элементы с таким же названием:

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

    <xsl:key name="keyItemName" match="ITEM_NAME" use="."/> 

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

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

    <xsl:template match="ITEM_NAME"> 
    <xsl:copy> 
     <xsl:value-of select="." /> 
     <xsl:if test="count(key('keyItemName', .)) > 1"> 
     <xsl:value-of select="concat('-', count(preceding::ITEM_NAME[. = current()]) + 2)"/> 
     </xsl:if> 
    </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

Когда запускаются на входе образца, это производит:

<Items> 
    <Item> 
    <ITEM_CODE>ITEM_CODE</ITEM_CODE> 
    <ITEM_NAME>ITEM_NAME</ITEM_NAME> 
    <ITEM_ALTERNATE_NAME>ITEM_ALTERNATE_NAME</ITEM_ALTERNATE_NAME> 
    <ITEM_CATEGORY_CODE>ITEM_CATEGORY_CODE</ITEM_CATEGORY_CODE> 
    </Item> 
    <Item> 
    <ITEM_CODE>15031</ITEM_CODE> 
    <ITEM_NAME>Outer Carton-2</ITEM_NAME> 
    <ITEM_ALTERNATE_NAME /> 
    <ITEM_CATEGORY_CODE>52401</ITEM_CATEGORY_CODE> 
    </Item> 
    <Item> 
    <ITEM_CODE>150529</ITEM_CODE> 
    <ITEM_NAME>Outer Carton-3</ITEM_NAME> 
    <ITEM_ALTERNATE_NAME /> 
    <ITEM_CATEGORY_CODE>52401</ITEM_CATEGORY_CODE> 
    </Item> 
    <Item> 
    <ITEM_CODE>150999</ITEM_CODE> 
    <ITEM_NAME>Outer Carton-4</ITEM_NAME> 
    <ITEM_ALTERNATE_NAME /> 
    <ITEM_CATEGORY_CODE>52401</ITEM_CATEGORY_CODE> 
    </Item> 
    <Item> 
    <ITEM_CODE>150988</ITEM_CODE> 
    <ITEM_NAME>test</ITEM_NAME> 
    <ITEM_ALTERNATE_NAME /> 
    <ITEM_CATEGORY_CODE>52401</ITEM_CATEGORY_CODE> 
    </Item> 
</Items> 
+0

Здравствуйте JLRishe, Спасибо за ваш ответ, он отлично работает. Я уже думал, что что-то с моим ключом было неправильным, так как я хочу только проверить ITEM_NAME, но не что-то еще. С наилучшими пожеланиями, Питер – Peter

+0

Добро пожаловать, но я думаю, что, возможно, неправильно понял ваши требования. У моего ответа есть счетчик (начиная с 2), чтобы указать одинаковые имена. Так что, если бы у вас была какая-то другая группа предметов с одинаковыми именами, то они были бы пронумерованы 2, 3, 4. Но, посмотрев на ответ Тима С, я думаю, что вы хотите, чтобы цифры были от первого элемента до последнего , но только показывать номер, если имя является дубликатом. Это верно? – JLRishe

+0

Здравствуйте, ваше решение отлично работает, но поскольку версия Тима использует только ключи и не имеет предшествующей конструкции, я пойду с его решением, потому что фактический XML, который у меня есть, огромен. Но я не понял вашу точку зрения: если мы сопоставляем только ITEM_NAME, никакие другие элементы не могут быть изменены. Как я уже сказал, ваш XSLT работает отлично, производительность мудрого Тима лучше. С наилучшими пожеланиями, Питер (+1) – Peter

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