如何使用转义标记更新XSLT中的XML节点(在<和>之间)

时间:2014-05-21 22:46:08

标签: xslt

  <Instance xsi:type="ButtonConfig">
    <Name>ExitButton</Name>
    <LayoutProperties xsi:type="Layout">
      <Rows>
        <Row>
          <Height>100</Height>
        </Row>
      </Rows>
      <Columns>
        <Column>
          <Width>1</Width>
        </Column>
        <Column>
          <Width>610</Width>
        </Column>
        <Column>
          <Width>100</Width>
        </Column>
        <Column>
          <Width>0</Width>
        </Column>
      </Columns>
    </LayoutProperties>
    <ItemXmlAttributes>
      &lt;AllItemsConfig&gt;
        &lt;ItemConfig&gt;
          &lt;ItemName&gt;ItemName1&lt;/ItemName&gt;
          &lt;Interval&gt;200&lt;/Interval&gt;
        &lt;/ItemConfig&gt;
        &lt;ItemConfig&gt;
          &lt;ItemName&gt;ItemName2&lt;/ItemName&gt;
          &lt;Interval&gt;500&lt;/Interval&gt;
        &lt;/ItemConfig&gt;
      &lt;/AllItemsConfig&gt;
    </ItemXmlAttributes>
  </Instance>

我有一个具有上述结构的xml。 Instance节点在xml文件中重复多次。 我需要在这个xml文件中进行两处更改:

如何使用XSLT将LayoutProperties中的第二列宽度从610更新为700? 如何使用XSLT在ItemXmlAttributes中将ItemName2的Interval从500更新为600?

1 个答案:

答案 0 :(得分:0)

我找到了一个使用XSLT 1.0和文本串联的解决方案,它允许您从转义的XML中提取数据。它涉及将文本存储到变量中并使用document()函数重新加载它。使用data URI scheme可以加载嵌入数据,就像使用语法:

的外部文档一样
data:[<mediatype>],<data>

<ItemXmlAttributes>标签的字符串内容读入变量,我们将有一个包含XML的字符串:

'<AllItemsConfig><ItemConfig> ... </ItemConfig></AllItemsConfig>'

但我们无法使用模板处理它,因为它是作为字符串加载的。它需要以某种方式转换为 nodeset

通过将URI Scheme附加到字符串的开头,可以将其视为嵌入式文档。根据{{​​3}},如果处理器支持URI方案,document()函数支持此功能。我尝试使用Saxon 6.5.5和Xalan并且它有效。这样:

document('data:text/xml,<AllItemsConfig><ItemConfig> ... </ItemConfig></AllItemsConfig>')

将字符串加载为可以使用模板处理的XML文档。

此模板:

<xsl:template match="ItemXmlAttributes">
    <xsl:variable name="input">
        <xsl:value-of select="."/>
    </xsl:variable>
    <xsl:copy>
        <xsl:apply-templates 
            select="document(concat('data:text/xml,',$input))/AllItemsConfig" />
    </xsl:copy>
</xsl:template>

将阅读<ItemXmlAttributes>的文字内容并将其存储在$input变量中。然后它将复制该元素,并将内容的模板应用为已解析的XML文档。

没有自动生成转义标记的方法。一种解决方案是直接打印转义的尖括号和标签名称。这是您的转义身份转换,用于未修改的文件转义部分中的元素:

<xsl:template match="*[ancestor-or-self::AllItemsConfig]">
    <xsl:text>&lt;</xsl:text>
    <xsl:value-of select="name()"/>
    <xsl:text>&gt;</xsl:text>
        <xsl:apply-templates/>
    <xsl:text>&lt;/</xsl:text>
    <xsl:value-of select="name()"/>
    <xsl:text>&gt;</xsl:text>
</xsl:template>

此模板选择Interval,其中ItemName兄弟包含&#34; ItemName1&#34;,并将内容更改为600.它仅打印文本。没有标签:

<xsl:template match="Interval[../ItemName='ItemName2']">
    <xsl:text>&lt;Interval&gt;</xsl:text>
    <xsl:text>600</xsl:text>
    <xsl:text>&lt;/Interval&gt;</xsl:text>
</xsl:template>

您的其他转换非常简单,大部分处理都是通过身份转换完成的。这个替换了第二列中的数据:

<xsl:template match="Column[2]">
    <xsl:copy>700</xsl:copy>
</xsl:template>

身份转换会不变地复制其他节点:

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

这是完整的样式表:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:preserve-space elements="Interval ItemName ItemConfig AllItemsConfig"/>

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

    <xsl:template match="Column[2]">
        <xsl:copy>700</xsl:copy>
    </xsl:template>

    <xsl:template match="ItemXmlAttributes">
        <xsl:variable name="input">
            <xsl:value-of select="."/>
        </xsl:variable>
        <xsl:copy>
            <xsl:apply-templates 
                select="document(concat('data:text/xml,',$input))/AllItemsConfig" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*[ancestor-or-self::AllItemsConfig]">
        <xsl:text>&lt;</xsl:text>
        <xsl:value-of select="name()"/>
        <xsl:text>&gt;</xsl:text>
            <xsl:apply-templates/>
        <xsl:text>&lt;/</xsl:text>
        <xsl:value-of select="name()"/>
        <xsl:text>&gt;</xsl:text>
    </xsl:template>

    <xsl:template match="Interval[../ItemName='ItemName2']">
        <xsl:text>&lt;Interval&gt;</xsl:text>
        <xsl:text>600</xsl:text>
        <xsl:text>&lt;/Interval&gt;</xsl:text>
    </xsl:template>

</xsl:stylesheet>

这是转型的结果:

<Instance xmlns:xsi="ns1" xsi:type="ButtonConfig">
   <Name>ExitButton</Name>
   <LayoutProperties xsi:type="Layout">
      <Rows>
         <Row>
            <Height>100</Height>
         </Row>
      </Rows>
      <Columns>
         <Column>
            <Width>1</Width>
         </Column>
         <Column>700</Column>
         <Column>
            <Width>100</Width>
         </Column>
         <Column>
            <Width>0</Width>
         </Column>
      </Columns>
   </LayoutProperties>
   <ItemXmlAttributes>&lt;AllItemsConfig&gt;
        &lt;ItemConfig&gt;
        &lt;ItemName&gt;ItemName1&lt;/ItemName&gt;
        &lt;Interval&gt;200&lt;/Interval&gt;
        &lt;/ItemConfig&gt;
        &lt;ItemConfig&gt;
        &lt;ItemName&gt;ItemName2&lt;/ItemName&gt;
        &lt;Interval&gt;600&lt;/Interval&gt;
        &lt;/ItemConfig&gt;
        &lt;/AllItemsConfig&gt;</ItemXmlAttributes>
</Instance>

XPath数据模型中等价处理CDATA部分中的转义标记和标记。如果字符串实际上是CDATA部分,或者您希望生成CDATA部分作为输出,则您不需要转义标记的模板,并且可以替换这两个模板的最后三个模板:

<xsl:template match="ItemXmlAttributes">
    <xsl:variable name="input">
        <xsl:value-of select="."/>
    </xsl:variable>
    <xsl:copy>
        <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
        <xsl:apply-templates select="document(concat('data:text/xml,',$input))/AllItemsConfig" />
        <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
    </xsl:copy>
</xsl:template>

<xsl:template match="Interval[../ItemName='ItemName2']">
    <xsl:copy>600</xsl:copy>
</xsl:template>

将生成<ItemXmlAttributes>元素:

<ItemXmlAttributes>
    <![CDATA[<AllItemsConfig>
       <ItemConfig>
          <ItemName>ItemName1</ItemName>
          <Interval>200</Interval>
       </ItemConfig>
       <ItemConfig>
          <ItemName>ItemName2</ItemName>
          <Interval>600</Interval>
       </ItemConfig>
    </AllItemsConfig>]]>
</ItemXmlAttributes>

与具有转义标记的文件相同(在XPath数据模型中)。