2016-10-14 6 views
0

У меня есть следующий XML-документ:XSLT: Добавить атрибут для всех потомков RootNode

$ cat data.xml 
<rootnode> 
<section id="1" > 
    <outer param="p1"> 
    <inner /> 
    <inner /> 
    </outer> 
    <outer param="p1"> 
    <inner /> 
    </outer> 
    <outer /> 
    <outer param="p5"/> 
</section> 
<section id="2" > 
    <outer > 
    <inner anotherparam="ap1"/> 
    <inner param="p4"/> 
    <inner /> 
    </outer> 
</section> 
</rootnode> 

Я хочу, чтобы добавить новый атрибут к каждому элементу, за исключением rootnode. Это преобразование XSLT делает почти то, что я хочу:

$ cat add.xsl 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 

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

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

</xsl:stylesheet> 

Однако он также добавляет новый атрибут rootnode. Как я могу опустить rootnode, чтобы он был просто скопирован?

ответ

1

Если вы добавите шаблон xsl, который соответствует rootnode, и просто выполните аналогичные действия, которые вы уже делаете для соответствия @*|node(), он не добавит атрибут.

Вот моя версия:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 

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

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

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

</xsl:stylesheet> 

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

<rootnode> 
    <section newattribute="NEW" id="1"> 
     <outer newattribute="NEW" param="p1"> 
      <inner newattribute="NEW"/> 
      <inner newattribute="NEW"/> 
     </outer> 
     <outer newattribute="NEW" param="p1"> 
      <inner newattribute="NEW"/> 
     </outer> 
     <outer newattribute="NEW"/> 
     <outer newattribute="NEW" param="p5"/> 
    </section> 
    <section newattribute="NEW" id="2"> 
     <outer newattribute="NEW"> 
      <inner newattribute="NEW" anotherparam="ap1"/> 
      <inner newattribute="NEW" param="p4"/> 
      <inner newattribute="NEW"/> 
     </outer> 
    </section> 
</rootnode> 
+0

Было бы лучше сделать последнее правило шаблона match = "*", поскольку вы полагаетесь на него, сопоставляя элементы, предпочитая первое правило. –

+0

@MichaelKay Я сделал редактирование - это то, что вы имеете в виду? –

+0

Да, это безопаснее (не всегда можно полагаться на последнее правило, которое выбирается при совпадении двух правил, но «*» имеет более высокий приоритет, чем «node()», так что все в порядке.) –

3

Я хотел бы предложить вам сделать это таким образом:

XSLT 1,0

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

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

<xsl:template match="*[not(self::rootnode)]"> 
    <xsl:copy> 
     <xsl:attribute name="newattribute">NEW</xsl:attribute> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
</xsl:template> 

</xsl:stylesheet> 
+0

На самом деле, я думаю, что это лучше, @nautical, пожалуйста, сделайте это принятым ответом. –

3

Я хочу добавить новый атрибут для каждого узла, кроме корневого.

Я считаю, что единственным элементом, в который вы хотите не добавить атрибут, является элемент документа (сверху). Это происходит в в этом документе XML, но в другом документе может быть другое имя, например topnode, и вы хотите, чтобы решение работало и в этом случае.

Кроме того, если у вас есть элемент с именем rootnode, который не является верхним элементом, вы, вероятно, хотите добавить новый атрибут к этому элементу.

Таким образом, следующее преобразование будет делать это, независимо от названия документа элемента:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes"/> 

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

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

замечают шаблон спички наиважнейшей шаблона:

<xsl:template match="*/*"> 

Это соответствует каждому элементу, родительский узел которого также является элементом - эффективно исключая элемент top (document).

Когда преобразование применяется на поставленном XML документа:

<rootnode> 
    <section id="1" > 
     <outer param="p1"> 
      <inner /> 
      <inner /> 
     </outer> 
     <outer param="p1"> 
      <inner /> 
     </outer> 
     <outer /> 
     <outer param="p5"/> 
    </section> 
    <section id="2" > 
     <outer > 
      <inner anotherparam="ap1"/> 
      <inner param="p4"/> 
      <inner /> 
     </outer> 
    </section> 
</rootnode> 

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

<rootnode> 
    <section newattribute="NEW" id="1"> 
     <outer newattribute="NEW" param="p1"> 
      <inner newattribute="NEW"/> 
      <inner newattribute="NEW"/> 
     </outer> 
     <outer newattribute="NEW" param="p1"> 
      <inner newattribute="NEW"/> 
     </outer> 
     <outer newattribute="NEW"/> 
     <outer newattribute="NEW" param="p5"/> 
    </section> 
    <section newattribute="NEW" id="2"> 
     <outer newattribute="NEW"> 
      <inner newattribute="NEW" anotherparam="ap1"/> 
      <inner newattribute="NEW" param="p4"/> 
      <inner newattribute="NEW"/> 
     </outer> 
    </section> 
</rootnode> 

Когда преобразование - без каких-либо изменений - применяется к аналогичному документу (только элемент документа переименован в topnode):

<topnode> 
    <section id="1" > 
     <outer param="p1"> 
      <inner /> 
      <inner /> 
     </outer> 
     <outer param="p1"> 
      <inner /> 
     </outer> 
     <outer /> 
     <outer param="p5"/> 
    </section> 
    <section id="2" > 
     <outer > 
      <inner anotherparam="ap1"/> 
      <inner param="p4"/> 
      <inner /> 
     </outer> 
    </section> 
</topnode> 

снова правильный результат получается:

<topnode> 
    <section newattribute="NEW" id="1"> 
     <outer newattribute="NEW" param="p1"> 
      <inner newattribute="NEW"/> 
      <inner newattribute="NEW"/> 
     </outer> 
     <outer newattribute="NEW" param="p1"> 
      <inner newattribute="NEW"/> 
     </outer> 
     <outer newattribute="NEW"/> 
     <outer newattribute="NEW" param="p5"/> 
    </section> 
    <section newattribute="NEW" id="2"> 
     <outer newattribute="NEW"> 
      <inner newattribute="NEW" anotherparam="ap1"/> 
      <inner newattribute="NEW" param="p4"/> 
      <inner newattribute="NEW"/> 
     </outer> 
    </section> 
</topnode> 

И в случае, имеющего этот источник XML-документ<rootnode> элемент был добавлен, что это не верхний элемент):

<rootnode> 
    <section id="1" > 
     <outer param="p1"> 
      <inner /> 
      <inner /> 
     </outer> 
     <outer param="p1"> 
      <inner /> 
     </outer> 
     <outer /> 
     <outer param="p5"/> 
    </section> 
    <rootnode/> 
    <section id="2" > 
     <outer > 
      <inner anotherparam="ap1"/> 
      <inner param="p4"/> 
      <inner /> 
     </outer> 
    </section> 
</rootnode> 

Снова правильный результат получается тем же без изменений преобразование:

<rootnode> 
    <section newattribute="NEW" id="1"> 
     <outer newattribute="NEW" param="p1"> 
      <inner newattribute="NEW"/> 
      <inner newattribute="NEW"/> 
     </outer> 
     <outer newattribute="NEW" param="p1"> 
      <inner newattribute="NEW"/> 
     </outer> 
     <outer newattribute="NEW"/> 
     <outer newattribute="NEW" param="p5"/> 
    </section> 
    <rootnode newattribute="NEW"/> 
    <section newattribute="NEW" id="2"> 
     <outer newattribute="NEW"> 
      <inner newattribute="NEW" anotherparam="ap1"/> 
      <inner newattribute="NEW" param="p4"/> 
      <inner newattribute="NEW"/> 
     </outer> 
    </section> 
</rootnode> 

урок:

Указание точного совпадения шаблонов может сэкономить много работы!

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