2016-06-06 6 views
1

Это содержание образец XML я написал для объяснения цели,XSLT - Выберите узел из шаблонов на основе карты

<doc> 
    <array> 
     <?Table_type Small?> 
     <table> 
      <data>text</data> 
     </table> 
    </array> 

    <array> 
     <?Table_type Medium?> 
     <table> 
      <data>text</data> 
     </table> 
    </array> 

    <array> 
     <?Table_type Large?> 
     <table> 
      <data>text</data> 
     </table> 
    </array> 
</doc> 

Здесь Вы можете определить 3 типа таблиц, таблица, содержащая значение инструкции обработки Small, Medium и Большой. (в фактическом документе есть больше типов таблиц)

что я хочу сделать, проверив тип таблицы (идентифицируйте с помощью инструкции по обработке), добавьте size атрибут <data> узлов.

поскольку существует большое количество существующих в исходном документе я использует следующий метод XSL для выполнения этой задачи таблицы типов,

<xsl:variable name="table.type.mapping"> 
     <map parent='Small' mapto='10'/> 
     <map parent='Medium' mapto='20'/> 
     <map parent='Large' mapto='30'/> 
    </xsl:variable> 

    <xsl:template match="data[ancestor::array/processing-instruction('Table_type')=$table.type.mapping/map[@parent=ancestor::array/processing-instruction('Table_type')]/@parent]"> 
     <data size="{$table.type.mapping/map[@parent=ancestor::array/processing-instruction('Table_type')]/@mapto}"> 
      <xsl:apply-templates/> 
     </data> 
    </xsl:template> 

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

Но это не читает соответствующее значение атрибута с карты и помещается в соответствующем <data> узле ,

Мой ожидается выход,

<doc> 
    <array> 
     <?Table_type Small?> 
     <table> 
      <data size="10">text</data> 
     </table> 
    </array> 

    <array> 
     <?Table_type Medium?> 
     <table> 
      <data size="20">text</data> 
     </table> 
    </array> 

    <array> 
     <?Table_type Large?> 
     <table> 
      <data size="30">text</data> 
     </table> 
    </array> 
</doc> 

Любое предложение, как я могу изменить мой шаблон для чтения правильное значение с карты и добавить правильный атрибут в <data> узел?

ответ

3

Это может быть сделано очень удобно (и эффективно) с помощью ключа для поиска:

XSLT 2,0

<xsl:stylesheet version="2.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="*"/> 

<xsl:variable name="table.type.mapping"> 
    <map parent='Small' mapto='10'/> 
    <map parent='Medium' mapto='20'/> 
    <map parent='Large' mapto='30'/> 
</xsl:variable> 

<xsl:key name="size" match="map" use="@parent" /> 

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

<xsl:template match="data"> 
    <data size="{key('size', ancestor::array/processing-instruction('Table_type'), $table.type.mapping)/@mapto}"> 
     <xsl:apply-templates/> 
    </data> 
</xsl:template> 

</xsl:stylesheet> 
0

Вы попали в ловушку Resulting tree fragment, что является серьезной проблемой XSLT-1.0.

Один из способов избежать превращения вашего <xsl:variable> в остров данных в вашем XSLT-файле. Этот остров данных нуждается в собственном пространстве имен, которое я назвал var, который должен быть явно исключен из результата, используя директиву exclude-result-prefixes.

Кроме того, я использовал две переменные, чтобы избежать конфликтов пространства имен между XML и пространством имен XSLT.

FYI: document('')/xsl:stylesheet относится к корневому узлу XML текущего документа XSLT.

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:var="some.var" exclude-result-prefixes="var"> 
    <xsl:output method="xml" indent="yes" /> 

    <var:tabletypemapping> 
     <map parent='Small' mapto='10'/> 
     <map parent='Medium' mapto='20'/> 
     <map parent='Large' mapto='30'/> 
    </var:tabletypemapping> 

    <xsl:template match="data"> 
    <xsl:variable name="procIns" select="ancestor::array/processing-instruction('Table_type')" /> 
    <xsl:variable name="mapIns" select="document('')/xsl:stylesheet/var:tabletypemapping/map[@parent = $procIns]/@mapto" /> 
    <data size="{$mapIns}"> 
     <xsl:apply-templates/> 
    </data> 
    </xsl:template> 

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

</xsl:stylesheet> 

Выход:

<?xml version="1.0"?> 
<doc> 
    <array> 
     <?Table_type Small?> 
     <table> 
      <data size="10">text</data> 
     </table> 
    </array> 

    <array> 
     <?Table_type Medium?> 
     <table> 
      <data size="20">text</data> 
     </table> 
    </array> 

    <array> 
     <?Table_type Large?> 
     <table> 
      <data size="30">text</data> 
     </table> 
    </array> 
</doc> 
+0

Этот вопрос помечается XSLT 2.0. –

+0

@ michael.hor257k: Конечно, ваше право. Я просто узнал, что после публикации моего ответа. – zx485

1

Вы, наверное, не нужно сложное выражение XPath в самой игре, особенно если все data элементы имеют действительную инструкцию по обработке перед ними.

Основная проблема заключается в использовании AVT для вычисления атрибута size. Он ищет предка элемента map, а не текущий элемент data. Это должно быть ...

<data size="{$table.type.mapping/map[@parent=current()/ancestor::array/processing-instruction('Table_type')]/@mapto}"> 

Попробуйте XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> 
<xsl:variable name="table.type.mapping"> 
     <map parent='Small' mapto='10'/> 
     <map parent='Medium' mapto='20'/> 
     <map parent='Large' mapto='30'/> 
    </xsl:variable> 

    <xsl:template match="data"> 
     <data size="{$table.type.mapping/map[@parent=current()/ancestor::array/processing-instruction('Table_type')]/@mapto}"> 
      <xsl:apply-templates/> 
     </data> 
    </xsl:template> 

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

Если некоторые data элементы не имеют соответствующих инструкций по обработке, попробуйте этот XSLT вместо

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> 
<xsl:variable name="table.type.mapping"> 
     <map parent='Small' mapto='10'/> 
     <map parent='Medium' mapto='20'/> 
     <map parent='Large' mapto='30'/> 
    </xsl:variable> 

    <xsl:template match="data"> 
     <data> 
      <xsl:variable name="size" select="$table.type.mapping/map[@parent=current()/ancestor::array/processing-instruction('Table_type')]/@mapto" /> 
      <xsl:if test="$size"> 
       <xsl:attribute name="size" select="$size" /> 
      </xsl:if> 
      <xsl:apply-templates/> 
     </data> 
    </xsl:template> 

    <xsl:template match="node()|@*"> 
     <xsl:copy> 
      <xsl:apply-templates select="node()|@*"/> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 
Смежные вопросы