2017-04-12 126 views
2

我有一个相当平坦的XML文件,我想要更改某些属性,具体取决于某种输入列表。我无法解决的棘手部分是我也想要不仅在一个节点上而且在引用找到的节点的兄弟节点上更改属性。XSLT转换使用属性作为输入来更改同级属性

我有下面的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> 

"Second""Third"name值产品标签匹配,它们的cls属性值改为ClassB,以及相关SubItem元素cls属性值(主属性引用Item元素上的id属性)。

这是可能的所有与XSLT或我需要使用一些编程?

+0

你可以依靠每一个''在同与''被关联文档,通过'SubItem/@ master'和'Item/@ id'?另外,你是否需要保留元素顺序? –

+0

我的问题是,你可以设想重构你的样式表,以便''的模板模板不直接将模板应用于''子模板,而是依赖于模板() '将模板应用于相关的''。然后,您将拥有足够的上下文来正确指导他们的'cls'属性应该如何转换。 –

+1

XSLT _is_ programming ;-) –

回答

0

您可以创建一个xsl:键来引用SubItem中的Item。您可以使用单个模板并使用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>