XSLT转换使用属性作为输入来更改同级属性

时间:2017-04-12 19:09:42

标签: xml xslt

我有一个非常扁平的XML文件,我想根据某种输入列表更改一些属性。我无法解决的棘手问题是我不仅要在一个节点上更改属性,还要在引用找到的节点的兄弟节点上更改属性。

我有以下XML文件:

<?xml version="1.0" encoding="utf-8"?>
<Root>
    <SubItem id="id21" cls="classA" name="FirstSub" master="#id30"/>
    <SubItem id="id22" cls="classA" name="SecondSub" master="#id31"/>
    <SubItem id="id23" cls="classA" name="ThirdSub" master="#id32"/>
    <SubItem id="id24" cls="classA" name="FourthSub" master="#id33"/>
    <SubItem id="id25" cls="classA" name="FifthSub" master="#id34"/>
    <Item id="id30" cls="classA" name="First"/>
    <Item id="id31" cls="classA" name="Second"/>
    <Item id="id32" cls="classA" name="Third"/>
    <Item id="id33" cls="classA" name="Fourth"/>
    <Item id="id34" cls="classA" name="Fifth" />
</Root>

以下附加输入文件列出了我想要更改name属性值的元素的cls值:

<input>
    <ToClassB>
        <Name>Second</Name>
        <Name>Third</Name>
    </ToClassB>
</input>

以下XSLT,适用于name值与其他输入列表中的值相匹配的元素:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:plm="http://www.plmxml.org/Schemas/PLMXMLSchema" exclude-result-prefixes="xs"
    version="2.0">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="no"/>

    <xsl:variable name="inputs" select="document('file:/C:/Temp//demoInput.xml')"/>

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

    <xsl:template match="/Root/Item/@name[. = $inputs/input/ToClassB/Name/text()]">
        <xsl:variable name="elemName" select="../@id"/>
        <xsl:copy>
            <xsl:copy-of select="../@name"/>
        </xsl:copy>
        <xsl:attribute name="cls">
            <xsl:value-of select="'classB'" />
        </xsl:attribute>

    </xsl:template>
</xsl:stylesheet>

我的预期结果:

<?xml version="1.0" encoding="UTF-8"?>
<Root>
    <SubItem id="id21" cls="classA" name="FirstSub" master="#id30"/>
    <SubItem id="id22" cls="ClassB" name="SecondSub" master="#id31"/>
    <SubItem id="id23" cls="ClassB" name="ThirdSub" master="#id32"/>
    <SubItem id="id24" cls="classA" name="FourthSub" master="#id33"/>
    <SubItem id="id25" cls="classA" name="FifthSub" master="#id34"/>
    <Item id="id30" cls="classA" name="First"/>
    <Item id="id31" cls="ClassB" name="Second"/>
    <Item id="id32" cls="ClassB" name="Third"/>
    <Item id="id33" cls="classA" name="Fourth"/>
    <Item id="id34" cls="classA" name="Fifth"/>
</Root>

name值为"Second""Third"的商品代码匹配,其cls属性值更改为ClassB,以及{ {1}}相关cls元素的属性值(SubItem元素上的主属性引用ID属性)。

这对XSLT是否可行?或者我是否需要使用某些编程?

1 个答案:

答案 0 :(得分:0)

您可以创建一个xsl:键,以引用Item中的SubItem。您可以使用单个模板,并使用idmaster属性来访问密钥。

示例...

XSLT 2.0

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

  <xsl:key name="itemsByID" match="Item" use="@id"/>

  <xsl:variable name="inputs" 
    select="document('demoInput.xml')/input/ToClassB/Name"/>

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

  <xsl:template match="Item|SubItem">
    <xsl:variable name="refid" 
      select="if (@master) then substring-after(@master,'#') else @id"/>
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:attribute name="cls" 
        select="if (key('itemsByID',$refid)/@name = $inputs) 
        then 'ClassB' else @cls"/>
      <xsl:apply-templates select="node()"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

<强>输出

<Root>
   <SubItem id="id21" cls="classA" name="FirstSub" master="#id30"/>
   <SubItem id="id22" cls="ClassB" name="SecondSub" master="#id31"/>
   <SubItem id="id23" cls="ClassB" name="ThirdSub" master="#id32"/>
   <SubItem id="id24" cls="classA" name="FourthSub" master="#id33"/>
   <SubItem id="id25" cls="classA" name="FifthSub" master="#id34"/>
   <Item id="id30" cls="classA" name="First"/>
   <Item id="id31" cls="ClassB" name="Second"/>
   <Item id="id32" cls="ClassB" name="Third"/>
   <Item id="id33" cls="classA" name="Fourth"/>
   <Item id="id34" cls="classA" name="Fifth"/>
</Root>