2016-08-30 3 views
0

Мой исходный xml имеет разные узлы с тем же именем тега. Я хочу преобразовать этот xml в xml, где каждый дочерний узел уникален, например. это мой XML:Скопируйте только первый дочерний элемент на вывод

<?xml version="1.0" encoding="utf-16"?> 
<shiporder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" orderid="orderid1"> 
    <orderperson>orderperson1</orderperson> 
    <shipto> 
    <name>name1</name> 
    <address>address1</address> 
    <city>city1</city> 
    <country>country1</country> 
    </shipto> 
    <item> 
    <title>title1</title> 
    <note>note1</note> 
    <note>1</note> 
    </item> 
    <item> 
    <title>title2</title> 
    <note>note2</note> 
    </item> 
</shiporder> 

Результат после моей трансформации должен выглядеть следующим образом:

<?xml version="1.0" encoding="utf-16"?> 
<shiporder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" orderid="orderid1"> 
    <orderperson>orderperson1</orderperson> 
    <shipto> 
    <name>name1</name> 
    <address>address1</address> 
    <city>city1</city> 
    <country>country1</country> 
    </shipto> 
    <item> 
    <title>title1</title> 
    <note>note1</note> 
    </item> 
</shiporder> 

Я пытался выбрать первый ребенок с помощью *[1], если есть более чем один раз с таким же именем тега, но до сих пор Я не получаю правильный результат:

<xsl:template match="/"> 
     <xsl:copy-of select="//*[1]"/> 
</xsl:template> 

ответ

1

Использование XSLT 2.0, вы можете попробовать

<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:strip-space elements="*"/> 
    <xsl:output indent="yes"/> 

    <xsl:key name="name" match="*" use="node-name(.)"/> 

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

    <xsl:template match="*[not(. is key('name', node-name(.), ..)[1])]"/> 

</xsl:stylesheet> 

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

<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:strip-space elements="*"/> 
    <xsl:output indent="yes"/> 

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

    <xsl:template match="*[preceding-sibling::*[node-name(.) eq node-name(current())]]"/> 

</xsl:stylesheet> 
+0

thx за исключением вложенного шаблона. Не могли бы вы добавить некоторые пояснения к циклу шаблона, который определяется '* [previous-sibling :: * [node-name (.) Eq node-name (current())]]'? – StellaMaris

+0

Образец '* [previous-sibling :: * [node-name (.) Eq node-name (current())]]' соответствует любому элементу, у которого есть предшествующий элемент сиблинга того же квалифицированного имени, то есть имеет предшествующий элемент сиблинга того же локального имени в том же пространстве имен. –

+0

Но тогда я не понимаю, почему он не копирует все другие ноты с именем «item», у которого есть предыдущий брат? – StellaMaris

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