2013-05-09 2 views
0

Мне нужно изменить атрибут родительского узла на основе комбинации значения родительского attirbute и дочернего значения. Мой вход XML, как показано ниже:Изменить значение родительского атрибута на основе дочернего значения

<filters> 
<sheetFilter filterUsage="table" labelKey="WR" hidden="false"> 
    <userLogin>U0002</userLogin> 
    <containers> 
      <sheetTypeRef name="WorkRequest"/> 
    </containers> 
</sheetFilter> 
<sheetFilter filterUsage="table" labelKey="AR" hidden="false"> 
    <userLogin>U0003</userLogin> 
    <containers> 
      <sheetTypeRef name="ARRequest"/> 
    </containers> 
</sheetFilter> 
<sheetFilter filterUsage="table" labelKey="WR" hidden="false"> 
    <userLogin>U0002</userLogin> 
    <containers> 
      <sheetTypeRef name="WorkRequest"/> 
    </containers> 
</sheetFilter> 
</filters> 

В случае @labelKey и userLogin значения комбинации повторяющейся, я должен заменить @labelKey со счетчиком appeneded и желаемого выхода должно быть, как:

<filters>  
    <sheetFilter filterUsage="table" labelKey="WR1" hidden="false"> 
     <userLogin>U0002</userLogin> 
     <containers> 
      <sheetTypeRef name="WorkRequest"/> 
     </containers> 
    </sheetFilter> 
    <sheetFilter filterUsage="table" labelKey="AR" hidden="false"> 
     <userLogin>U0003</userLogin> 
     <containers> 
      <sheetTypeRef name="WorkRequest"/> 
     </containers> 
    </sheetFilter> 
    <sheetFilter filterUsage="table" labelKey="WR2" hidden="false"> 
     <userLogin>U0002</userLogin> 
     <containers> 
      <sheetTypeRef name="WorkRequest"/> 
     </containers> 
    </sheetFilter> 
</filters> 

Я написал ниже XSLT, чтобы применить трансформацию:

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

<xsl:template match="sheetFilter[@labelKey='WR']"> 
    <xsl:param name="i" select="1" /> 
    <xsl:element name="{ local-name() }" disable-output-escaping="yes"> 

    <xsl:for-each select="userLogin[text()='U0002']" > 
     <xsl:with-param name="i" select="$i +1"/> 
     <xsl:if test="not(../sheetFilter[@labelKey])"> 
     <xsl:apply-templates select="../@*"/> 
     </xsl:if> 

     <xsl:attribute name="labelKey"> 
     <xsl:value-of select="concat('WR', $i)"/> 
     </xsl:attribute> 
    </xsl:for-each> 
    <xsl:apply-templates select="node()"/> 
    </xsl:element> 
</xsl:template> 

Но я получаю предупреждение компилятора ниже:

Compiler warnings: 
Attribute 'labelKey' outside of element 

И выход не соответствует, в некоторых узлах значение счетчика применяется к «labelKey» и в некоторых узлах @lableKey сам отсутствует. Может кто-нибудь пролить свет, что пошло не так в вышеупомянутом xslt? Также я хотел бы знать, можно ли обобщить условие, например match="sheetFilter[@labelKey='WR']" можно заменить WR и U0002 на обобщенный оператор, так как я не уверен в значениях комбинации, которые могут повторяться.

Заранее спасибо. Susan

ответ

0

Если исходный порядок элементов sheetFilter не матер, вы можете использовать что-то на основе MUENCHIAN МЕТОДЫ. Это также будет работать с xlt-1.0.

Попробуйте это:

<?xml version="1.0"?> 
<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0"> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:key name="kSheetFilter" match="sheetFilter " use="concat(@labelKey,'#',userLogin)" /> 

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

    <xsl:template match="sheetFilter" > 
     <xsl:param name="pos" /> 
     <xsl:param name="copy_cnt"/> 
     <xsl:copy> 
      <xsl:apply-templates select="@* "/> 
      <xsl:if test="$copy_cnt &gt; '1'"> 
       <xsl:attribute name="labelKey" > 
        <xsl:value-of select="concat(@labelKey, $pos)"/> 
       </xsl:attribute> 
      </xsl:if> 
      <xsl:apply-templates select="node()"/> 
     </xsl:copy> 

    </xsl:template> 
    <xsl:template match="/*"> 
     <xsl:copy> 
      <xsl:for-each 
       select="sheetFilter[ generate-id()= 
      generate-id(key('kSheetFilter', concat(@labelKey,'#',userLogin) 
        ) [1])]" > 
       <xsl:variable name="sheets" select="key('kSheetFilter', concat(@labelKey,'#',userLogin))" /> 
       <xsl:for-each select=" $sheets" > 
       <xsl:apply-templates select="."> 
        <xsl:with-param name="pos" select="position()"/> 
        <xsl:with-param name ="copy_cnt" select="count($sheets)" /> 
       </xsl:apply-templates> 
       </xsl:for-each> 
      </xsl:for-each> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

Это сгенерирует следующий вывод:

<filters> 
    <sheetFilter filterUsage="table" labelKey="WR1" hidden="false"> 
       <userLogin>U0002</userLogin> 
       <containers> 
         <sheetTypeRef name="WorkRequest"/> 
       </containers> 
     </sheetFilter> 
    <sheetFilter filterUsage="table" labelKey="WR2" hidden="false"> 
       <userLogin>U0002</userLogin> 
       <containers> 
         <sheetTypeRef name="WorkRequest"/> 
       </containers> 
     </sheetFilter> 
    <sheetFilter filterUsage="table" labelKey="AR" hidden="false"> 
       <userLogin>U0003</userLogin> 
       <containers> 
         <sheetTypeRef name="ARRequest"/> 
       </containers> 
     </sheetFilter> 
</filters> 
+0

Для меня это не имеет значения. Решение отлично работает. Еще раз спасибо. – smj100

0

Ваш общий XSLT не подходит. У меня есть создать новый XSLT, чтобы получить нужный результат:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes"/> 

    <xsl:template match="filters"> 
    <filters> 
     <xsl:call-template name="abc"> 
     <xsl:with-param name="filter" select="."/> 
     </xsl:call-template> 
    </filters> 
    </xsl:template> 

    <xsl:template name="abc" match="//sheetFilter"> 
    <xsl:param name="filter"/> 
    <xsl:for-each select="$filter/child::*"> 
     <xsl:variable name="labelKey" select="@labelKey"/> 
     <xsl:variable name="userLogin" select="userLogin"/> 
     <sheetFilter filterUsage="{@filterUsage}" 
     labelKey="{if (count(//sheetFilter[@labelKey = $labelKey][userLogin = $userLogin]) gt 1) 
        then concat(@labelKey,sum(count(preceding-sibling::sheetFilter[@labelKey=$labelKey])+1)) 
        else @labelKey 
        }" 
     hidden="{@hidden}"> 
     <xsl:copy-of select="child::*"/> 
     </sheetFilter> 
    </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

sample1 XML:

<filters> 
    <sheetFilter filterUsage="table" labelKey="WR" hidden="false"> 
    <userLogin>U0002</userLogin> 
    <containers> 
     <sheetTypeRef name="WorkRequest"/> 
    </containers> 
    </sheetFilter> 
    <sheetFilter filterUsage="table" labelKey="AR" hidden="false"> 
    <userLogin>U0003</userLogin> 
    <containers> 
     <sheetTypeRef name="ARRequest"/> 
    </containers> 
    </sheetFilter> 
    <sheetFilter filterUsage="table" labelKey="WR" hidden="false"> 
    <userLogin>U0002</userLogin> 
    <containers> 
     <sheetTypeRef name="WorkRequest"/> 
    </containers> 
    </sheetFilter> 
</filters> 

ВЫВОД:

<filters> 
    <sheetFilter filterUsage="table" labelKey="WR1" hidden="false"> 
     <userLogin>U0002</userLogin> 
     <containers> 
     <sheetTypeRef name="WorkRequest"/> 
     </containers> 
    </sheetFilter> 
    <sheetFilter filterUsage="table" labelKey="AR" hidden="false"> 
     <userLogin>U0003</userLogin> 
     <containers> 
     <sheetTypeRef name="ARRequest"/> 
     </containers> 
    </sheetFilter> 
    <sheetFilter filterUsage="table" labelKey="WR2" hidden="false"> 
     <userLogin>U0002</userLogin> 
     <containers> 
     <sheetTypeRef name="WorkRequest"/> 
     </containers> 
    </sheetFilter> 
</filters> 

sample2 XML:

<filters> 
    <sheetFilter filterUsage="table" labelKey="WR" hidden="false"> 
    <userLogin>111U0002</userLogin> 
    <containers> 
     <sheetTypeRef name="WorkRequest"/> 
    </containers> 
    </sheetFilter> 
    <sheetFilter filterUsage="table" labelKey="AR" hidden="false"> 
    <userLogin>U0003</userLogin> 
    <containers> 
     <sheetTypeRef name="ARRequest"/> 
    </containers> 
    </sheetFilter> 
    <sheetFilter filterUsage="table" labelKey="WR" hidden="false"> 
    <userLogin>U0002</userLogin> 
    <containers> 
     <sheetTypeRef name="WorkRequest"/> 
    </containers> 
    </sheetFilter> 
</filters> 

ВЫВОД:

<?xml version="1.0" encoding="UTF-8"?> 
<filters> 
    <sheetFilter filterUsage="table" labelKey="WR" hidden="false"> 
     <userLogin>111U0002</userLogin> 
     <containers> 
     <sheetTypeRef name="WorkRequest"/> 
     </containers> 
    </sheetFilter> 
    <sheetFilter filterUsage="table" labelKey="AR" hidden="false"> 
     <userLogin>U0003</userLogin> 
     <containers> 
     <sheetTypeRef name="ARRequest"/> 
     </containers> 
    </sheetFilter> 
    <sheetFilter filterUsage="table" labelKey="WR" hidden="false"> 
     <userLogin>U0002</userLogin> 
     <containers> 
     <sheetTypeRef name="WorkRequest"/> 
     </containers> 
    </sheetFilter> 
</filters> 

sample3 XML:

<filters> 
    <sheetFilter filterUsage="table" labelKey="" hidden="false"> 
    <userLogin>U0002</userLogin> 
    <containers> 
     <sheetTypeRef name="WorkRequest"/> 
    </containers> 
    </sheetFilter> 
    <sheetFilter filterUsage="table" labelKey="AR" hidden="false"> 
    <userLogin>U0003</userLogin> 
    <containers> 
     <sheetTypeRef name="ARRequest"/> 
    </containers> 
    </sheetFilter> 
    <sheetFilter filterUsage="table" labelKey="WR" hidden="false"> 
    <userLogin>U0002</userLogin> 
    <containers> 
     <sheetTypeRef name="WorkRequest"/> 
    </containers> 
    </sheetFilter> 
</filters> 

ВЫВОД:

<?xml version="1.0" encoding="UTF-8"?> 
<filters> 
    <sheetFilter filterUsage="table" labelKey="" hidden="false"> 
     <userLogin>U0002</userLogin> 
     <containers> 
     <sheetTypeRef name="WorkRequest"/> 
     </containers> 
    </sheetFilter> 
    <sheetFilter filterUsage="table" labelKey="AR" hidden="false"> 
     <userLogin>U0003</userLogin> 
     <containers> 
     <sheetTypeRef name="ARRequest"/> 
     </containers> 
    </sheetFilter> 
    <sheetFilter filterUsage="table" labelKey="WR" hidden="false"> 
     <userLogin>U0002</userLogin> 
     <containers> 
     <sheetTypeRef name="WorkRequest"/> 
     </containers> 
    </sheetFilter> 
</filters> 
+0

Благодарим за ответ.Будет ли вышеупомянутый xslt хорош для 1.1? Когда я попытался, я получил следующую ошибку: ERROR: «Синтаксическая ошибка в« null ». FATAL ERROR: 'Не удалось собрать таблицу стилей' javax.xml.transform.TransformerConfigurationException: Не удалось составить таблицу стилей в com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl.newTemplates (TransformerFactoryImpl.java:828) at com.airbus.sysecc.util.SyseccXSLT.main (SyseccXSLT.java:91) – smj100

+0

Он с 2.0. Вы должны выбрать первый, который находится в 1.0 –

0

только для бухгалтерского учета: Вот решение, которое поддерживает порядок и делает работу без наличия для каждого из них.

version="1.0"> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:key name="kSheetFilter" match="sheetFilter " use="concat(@labelKey,'#',userLogin)" /> 

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

    <xsl:template match="sheetFilter" > 
     <xsl:param name="pos" /> 
     <xsl:param name="copy_cnt"/> 
     <xsl:copy> 
      <xsl:apply-templates select="@* "/> 
      <xsl:variable name="sheets" select="key('kSheetFilter',concat(@labelKey,'#',userLogin))" /> 
      <xsl:if test="count($sheets) &gt; '1'"> 
       <xsl:attribute name="labelKey" > 
        <xsl:value-of select="concat(@labelKey, 
            count(preceding-sibling::sheetFilter 
            [ 
            @labelKey = current()/@labelKey and 
            userLogin = current()/userLogin 
            ]) +1 
           )"/> 
       </xsl:attribute> 
      </xsl:if> 
      <xsl:apply-templates select="node()"/> 
     </xsl:copy> 

    </xsl:template> 

</xsl:stylesheet>