2009-07-23 4 views
1

У нас есть документы xml, которые содержат множество отмеченных узлов, таких как isProduct, isActive, isMandatory, где текст узла может быть True или False.Generic Xml Обработка документов

Это необходимо, чтобы манипулировать документы и сохранить их структуру, но преобразовать вышеуказанные узлы в словесное представление, как показано ниже:

<isProduct>True</ isProduct > ===> <Type>Product<Type> 
<isProduct>False</ isProduct > ===> <Type/> 

И то же самое для других узлов флага.

Мы ищем расширяемое и масштабируемое решение, которое можно настроить с минимальным трением после развертывания.

Расширяемый; мы имеем в виду, что будет больше случаев; как 2 флага, которые представляют статус; то есть isEmployee и isCustomer используется в документе для представления 4 разных именованных вещей; поэтому 4 возможные комбинации должны быть переведены только в одну строку, например «Сотрудник», «Клиент», «Клиент-Сотрудник» или «Нет».

Масштабируемым; мы имеем в виду, что его можно использовать для обработки любого документа XML без предварительного понимания его схемы и без ограничения размера документа.

Мы понимаем, что это можно сделать с помощью XSLT, можем ли мы написать XSLT, чтобы принять любой документ и создать тот же документ с добавленными или обновленными дополнительными узлами?

+0

так что должно быть сделано, если узел имеет ' Правда' а также ' True '? –

ответ

2

Предполагая, что входной сигнал так:

<gizmo> 
    <isProduct>True</isProduct> 
    <isFoo>False</isFoo> 
    <isBar>True</isBar> 
</gizmo> 

Общий подход будет:

<xsl:template match="gizmo"> 
    <xsl:copy> 
    <xsl:apply-templates select="*" /> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="*[substring(local-name(), 1, 2) = 'is']"> 
    <Type> 
    <xsl:if test=". = 'True'"> 
     <xsl:value-of select="substring-after(local-name(), 'is')" /> 
    </xsl:if> 
    </Type> 
</xsl:template> 

Что производит:

<gizmo> 
    <Type>Product</Type> 
    <Type /> 
    <Type>Bar</Type> 
</gizmo> 

Еще более обобщенный подход использует (в значительной степени) модифицированный тождественное преобразование:

<!-- the identity template... well, sort of --> 
<xsl:template match="node() | @*"> 
    <xsl:copy> 
    <!-- all element-type children that begin with 'is' --> 
    <xsl:variable name="typeNodes" select=" 
     *[substring(local-name(), 1, 2) = 'is'] 
    " /> 

    <!-- all other children (incl. elements that don't begin with 'this ' --> 
    <xsl:variable name="otherNodes" select=" 
     @* | node()[not(self::*) or self::*[substring(local-name(), 1, 2) != 'is']] 
    " /> 

    <!-- identity transform all the "other" nodes --> 
    <xsl:apply-templates select="$otherNodes" /> 

    <!-- collapse all the "type" nodes into a string --> 
    <xsl:if test="$typeNodes"> 
     <Type> 
     <xsl:variable name="typeString"> 
      <xsl:apply-templates select="$typeNodes" /> 
     </xsl:variable> 
     <xsl:value-of select="substring-after($typeString, '-')" /> 
     </Type> 
    </xsl:if> 
    </xsl:copy> 
</xsl:template> 

<!-- this collapses all the "type" nodes into a string --> 
<xsl:template match="*[substring(local-name(), 1, 2) = 'is']"> 
    <xsl:if test=". = 'True'"> 
    <xsl:text>-</xsl:text> 
    <xsl:value-of select="substring-after(local-name(), 'is')" /> 
    </xsl:if> 
</xsl:template> 

<!-- prevent the output of empty text nodes --> 
<xsl:template match="text()"> 
    <xsl:if test="normalize-space() != ''"> 
    <xsl:value-of select="." /> 
    </xsl:if> 
</xsl:template> 

выше принимает любые входные XML-бы то ни было и выводит ту же структуру, только элементы, названные <is*> свернуты в одну <Type> узел в виде штрих-разделителями строки:

<!-- in --> 
<foo> 
    <fancyNode /> 
    <gizmo> 
    <isProduct>True</isProduct> 
    <isFoo>False</isFoo> 
    <isBar>True</isBar> 
    </gizmo> 
</foo> 

<!-- out --> 
<foo> 
    <fancyNode /> 
    <gizmo> 
    <Type>Product-Bar</Type> 
    </gizmo> 
</foo> 
+0

Шаблон копии также удаляет любые атрибуты из документов XML. – mkoeller

+0

Да, я знаю. Я хотел бы остановиться на том, как выбрать и обработать «интересные» узлы в моем первом примере. Я добавил обобщенное решение как второй способ сделать больше того, что описал ОП. – Tomalak

1

Вот решение в XSLT основан на преобразовании в идентичности:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="node() | @*"> 
    <xsl:copy> 
     <xsl:apply-templates select="node() | @*"/> 
    </xsl:copy> 
    </xsl:template> 
    <xsl:template match="isProduct"> 
    <xsl:choose> 
     <xsl:when test=". = 'True'"><Type>Product</Type></xsl:when> 
     <xsl:otherwise><Type/></xsl:otherwise> 
    </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 
+0

Итак, как это будет обрабатывать узел isEmployee? –

+0

Либо добавьте аналогичный шаблон, соответствующий «isEmployee», либо создайте данный шаблон, как в ответе Томалака. – mkoeller