2014-01-06 1 views
2

My (упрощенный) вход XML выглядит следующим образом:Дублировать узел() для каждого токена в внуке и заменить текст элемента внука токеном в XSLT 1.0?

<?xml version="1.0" encoding="utf-8"?> 
<root> 
    <recordList> 

    <record> 
     <id>16</id> 

     <MaterialGroup> 
     <material> 
      <term>metal, glass</term> 
     </material> 
     <material.notes /> 
     <material.part>body</material.part> 
     </MaterialGroup> 

     <MaterialGroup> 
     <material> 
      <term>wood</term> 
     </material> 
     <material.notes>fragile</material.notes> 
     <material.part>lid</material.part> 
     </MaterialGroup> 
    </record> 

    <record> 
     ... 
    </record> 

    </recordList> 
</root> 

Обратите внимание, что term может содержать разделенный запятыми список из нескольких материалов (metal, glass).

Желаемый результат:

Я хочу разделить material/term и нужно дублировать прародителя Material со всеми атрибутами и узлами для этого.

<?xml version="1.0" encoding="utf-8"?> 
... 
     <MaterialGroup> 
     <material> 
      <term>metal</term> 
     </material> 
     <material.notes /> 
     <material.part>body</material.part> 
     </MaterialGroup> 

     <MaterialGroup> 
     <material> 
      <term>glass</term> 
     </material> 
     <material.notes /> 
     <material.part>body</material.part> 
     </MaterialGroup> 

     <MaterialGroup> 
     <material> 
      <term>wood</term> 
     </material> 
     <material.notes>fragile</material.notes> 
     <material.part>lid</material.part> 
     </MaterialGroup> 
    </record> 
... 

Первый MaterialGroup копируется для каждого маркера в разделителями внучат элемента material/term и term текст установлен в положение маркера текста. material.parts и material.notes могут быть скопированы без изменений.

Моя таблица стилей:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" 
> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:variable name="separator" select="','"/> 

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


    <xsl:template match="material/term" mode="s"> 
    <xsl:param name="split_term"/> 
    <xsl:value-of select="$split_term"/> 
    </xsl:template> 


    <xsl:template match="MaterialGroup" name="tokenize"> 
    <xsl:param name="text" select="material/term"/> 

    <xsl:choose> 
     <xsl:when test="not(contains($text, $separator))"> 
     <xsl:copy> 
      <xsl:apply-templates/> 
      <xsl:apply-templates select="material/term" mode="s"> 
      <xsl:with-param name="split_term"> 
       <xsl:value-of select="normalize-space($text)"/> 
      </xsl:with-param> 
      </xsl:apply-templates> 

     </xsl:copy> 

     </xsl:when> 

     <xsl:otherwise> 
     <xsl:copy> 

      <xsl:apply-templates/> 
      <xsl:apply-templates select="material/term" mode="s"> 
      <xsl:with-param name="split_term"> 
       <xsl:value-of select="normalize-space(substring-before($text, $separator))"/> 
      </xsl:with-param> 
      </xsl:apply-templates> 

     </xsl:copy> 

     <xsl:call-template name="tokenize"> 
      <xsl:with-param name="text" select="substring-after($text, $separator)"/> 
     </xsl:call-template> 
     </xsl:otherwise> 
    </xsl:choose> 

    </xsl:template> 

</xsl:stylesheet> 

Фактический выход:

<?xml version="1.0" encoding="utf-8"?> 
<root> 
    <recordList> 

    <record> 
     <id>16</id> 

     <MaterialGroup> 
     <material> 
      <term>metal, glass</term> 
     </material> 
     <material.notes /> 
     <material.part>body</material.part> 
     metal 
     </MaterialGroup> 

     <MaterialGroup> 
     <material> 
      <term>metal, glass</term> 
     </material> 
     <material.notes /> 
     <material.part>body</material.part> 
     glass 
     </MaterialGroup> 

     <MaterialGroup> 
     <material> 
      <term>wood</term> 
     </material> 
     <material.notes>fragile</material.notes> 
     <material.part>lid</material.part> 
     wood 
     </MaterialGroup> 
    </record> 

    <record> 
     ... 
    </record> 
    </recordList> 
</root> 

Маркеры (metal, glass) происходят в виде текстовых элементов, как MaterialGroup детей, ниже material.parts. Текст, в котором он должен появиться (material/term), не изменился.

Я посмотрел на пару решений подобных проблем, но никакого успеха:

https://stackoverflow.com/a/5480198/2044940
https://stackoverflow.com/a/10430719/2044940
http://codesequoia.wordpress.com/2012/02/15/xslt-example-add-a-new-node-to-elements/
...

Любые идеи?


Edit: Решение Мартина, без режимов, как предложил Майкл:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" 
> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:param name="separator" select="', '"/> 

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


    <xsl:template match="material/term"> 
    <xsl:param name="term"/> 
    <xsl:copy> 
     <xsl:value-of select="$term"/> 
    </xsl:copy> 
    </xsl:template> 


    <xsl:template match="MaterialGroup" name="tokenize"> 
    <xsl:param name="text" select="material/term"/> 

    <xsl:choose> 
     <xsl:when test="not(contains($text, $separator))"> 
     <xsl:copy> 
      <xsl:apply-templates> 
      <xsl:with-param name="term" select="$text"/> 
      </xsl:apply-templates> 
     </xsl:copy> 
     </xsl:when> 

     <xsl:otherwise> 
     <xsl:copy> 
      <xsl:apply-templates> 
      <xsl:with-param name="term" select="substring-before($text, $separator)"/> 
      </xsl:apply-templates> 
     </xsl:copy> 

     <xsl:call-template name="tokenize"> 
      <xsl:with-param name="text" select="substring-after($text, $separator)"/> 
     </xsl:call-template> 
     </xsl:otherwise> 
    </xsl:choose> 

    </xsl:template> 

</xsl:stylesheet> 
+0

четко заданный вопрос +1 – Peter

ответ

4

Я думаю, что вам нужно передать свой член вокруг:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" 
> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:param name="separator" select="', '"/> 

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

    <xsl:template match="@* | node()" mode="s"> 
    <xsl:param name="term"/> 
    <xsl:copy> 
     <xsl:apply-templates select="@* | node()" mode="s"> 
     <xsl:with-param name="term" select="$term"/> 
     </xsl:apply-templates> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="material/term" mode="s"> 
    <xsl:param name="term"/> 
    <xsl:copy> 
     <xsl:value-of select="$term"/> 
    </xsl:copy> 
    </xsl:template> 


    <xsl:template match="MaterialGroup" name="tokenize"> 
    <xsl:param name="text" select="material/term"/> 

    <xsl:choose> 
     <xsl:when test="not(contains($text, $separator))"> 
     <xsl:copy> 
      <xsl:apply-templates mode="s"> 
      <xsl:with-param name="term" select="$text"/> 
      </xsl:apply-templates> 
     </xsl:copy> 

     </xsl:when> 

     <xsl:otherwise> 

     <xsl:copy> 
      <xsl:apply-templates mode="s"> 
      <xsl:with-param name="term" select="substring-before($text, $separator)"/> 
      </xsl:apply-templates> 
     </xsl:copy> 


     <xsl:call-template name="tokenize"> 
      <xsl:with-param name="text" select="substring-after($text, $separator)"/> 
     </xsl:call-template> 
     </xsl:otherwise> 
    </xsl:choose> 

    </xsl:template> 

</xsl:stylesheet> 

Таким образом, с ваш вход, я получаю

<root> 
    <recordList> 
     <record> 
     <id>16</id> 
     <MaterialGroup> 
      <material> 
       <term>metal</term> 
      </material> 
      <material.notes/> 
      <material.part>body</material.part> 
     </MaterialGroup> 
     <MaterialGroup> 
      <material> 
       <term>glass</term> 
      </material> 
      <material.notes/> 
      <material.part>body</material.part> 
     </MaterialGroup> 
     <MaterialGroup> 
      <material> 
       <term>wood</term> 
      </material> 
      <material.notes>fragile</material.notes> 
      <material.part>lid</material.part> 
     </MaterialGroup> 
     </record> 
     <record> 
     ... 
    </record> 
    </recordList> 
</root> 
+0

Awesome! Ваше решение с режимом удостоверения личности + работает отлично. Спасибо за этот быстрый ответ! Я сделаю отладочную работу, чтобы увидеть шаг разрешения шаг за шагом. – CoDEmanX

+0

+1, хорошая идея. Просто любопытно: не могли бы вы добавить параметр к шаблону идентичности по умолчанию и покончить с этим режимом? –

+0

@michael.hor257k, да, вы правы в этом режиме, я начал с опубликованного кода с использованием режима и превратился в рабочее решение, но теперь, глядя на полный код, вы правы, что режим не нужен, если мы поместим этот параметр в шаблон преобразования идентификатора режима по умолчанию/нет. –

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

  • Нет связанных вопросов^_^