3

我一直在尝试使用 XSLT 来解析 .net 配置文件(web.config/app.config),然后执行不同的操作(例如替换属性和创建新元素),并且进展顺利,但现在我'一直在尝试重新创建节点树,以防部分或全部不存在。不幸的是,我还没有让它工作。

我想知道是否有人可以帮助我?

示例 Web.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings>
    <add key="webpages:Version" value="2.0.0.0" />
    <add key="webpages:Enabled" value="false" />
    <add key="setting1" value="true" />
    <add key="setting2" value="true" />
    <add key="setting3" value="true" />
  </appSettings>
  <system.serviceModel>
    <client>
      <endpoint name="endpointName1" address="http://endpoint1/endpoint1Service.svc" binding="endpointServiceBinding" />
    </client>
  </system.serviceModel>
 </configuration>

我想这样做,以便我可以添加一个新节点或其他节点,而不会干扰任何其他节点并假设它不存在。

客户端证书节点(xpath?位于下方)

/configuration/system.serviceModel/behaviors/endpointBehaviors
       /behavior[@name=service1BehaviorName]/clientCredentials/clientCertificate

如果您害怕 web.config,他是问题的简化版本 :)

<Node1>
    <Node2>
        <Node3 name="1" value="value1" />
        <Node3 name="2" value="value3" />
    </Node2>
</Node1>

我需要有关如何执行以下步骤的信息

  1. 如果 Node2 不存在,则创建它
  2. 以下任一陈述
    • 创建一个具有 name="3" 的新 Node3
    • 修改name="2"的Node3的内容

我可以编写代码来添加一个新节点,但我真的不知道如何连接它们

<!-- This should copy everything/be the the base rule -->
<xsl:template name="CopyAll" match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<!-- This will check and see if node2 does not exist, and create it if it does not -->
<xsl:template name="rule_1" match="/Node1">
    <xsl:copy>
        <xsl:if test="not(/Node1/Node2)">
            <Node2>
            <xsl:call-template name="rule_2"/> <!-- call rule 2 to create a node3 -->
            </Node2>
        </xsl:if>
    </xsl:copy>
    <xsl:apply-templates /> <!-- Not sure why this is here, but it seems to need to be here in order to keep copying the xml file-->
</xsl:template>

<!-- Add node3 if it doesn't exist -->
<xsl:template name="rule_2" match="/Node1/Node2/">
    <xsl:if test="not(/Node1/Node2/Node3[@name=1/)>
        <Node3 name="1" value="newValue" />
    </xsl:if>
    <xsl:apply-templates /> <!-- Not sure why this is here, but it seems to need to be here in order to keep copying the xml file-->
 <xsl:template>

 <!-- Change the value of Node3 -->
 <xsl:template match="/Node1/Node2/node3[@name='1']">
<xsl:copy>
     <!-- Blanket statement for keeping all attributes -->
     <xsl:copy-of select ="@*" />
     <!-- Change the below attributes -->
     <xsl:attribute name="value">newValue</xsl:attribute>
     <xsl:apply-templates /><!-- Not sure why this is here, but it seems to need to be here in order to keep copying the xml file-->
</xsl:copy>
 </xsl:template>

编辑:我有另一个问题,但由于我的原始问题已解决,我继续将第一个答案标记为我的问题的答案。公平地说,Dimitre 的解决方案同样有效。

4

2 回答 2

4

这是一种比您最初的尝试更干净的方法。请记住,XPath 区分大小写,并且node3不同于Node3

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:exslt="http://exslt.org/common"
                exclude-result-prefixes="exslt">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:variable name="treeToAddNF">
    <Node2>
      <Node3 name="1" value="">
        <Node4>
          <Node5/>
        </Node4>
      </Node3>
    </Node2>
  </xsl:variable>
  <xsl:variable name="treeToAdd" select="exslt:node-set($treeToAddNF)" />

  <xsl:template match="@*|node()" name="Copy">
    <xsl:param name="contentsToAdd" select="/.." />
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
      <xsl:apply-templates select="$contentsToAdd" />
    </xsl:copy>
  </xsl:template>

  <!-- Add Node2 to any Node1 that does not have a Node2 -->
  <xsl:template match="Node1[not(Node2)]">
    <xsl:call-template name="Copy">
      <xsl:with-param name="contentsToAdd" select="$treeToAdd/Node2" />
    </xsl:call-template>
  </xsl:template>

  <!-- Add node3 if it doesn't exist -->
  <xsl:template match="Node2[not(Node3/@name = 1)]">
    <xsl:call-template name="Copy">
      <xsl:with-param name="contentsToAdd" select="$treeToAdd/Node2/*" />
    </xsl:call-template>
  </xsl:template>

  <xsl:template match="Node3[@name = 1][not(Node4)]">
    <xsl:call-template name="Copy">
      <xsl:with-param name="contentsToAdd" select="$treeToAdd/Node2/Node3/*" />
    </xsl:call-template>
  </xsl:template>

  <xsl:template match="Node3[@name = 1]/Node4[not(Node5)]">
    <xsl:call-template name="Copy">
      <xsl:with-param name="contentsToAdd" select="$treeToAdd/Node2/Node3/Node4/*" />
    </xsl:call-template>
  </xsl:template>

  <xsl:template match="Node3[@name='1']/@value">
    <xsl:attribute name="value">newValue</xsl:attribute>
  </xsl:template>
</xsl:stylesheet>

在此输入上运行时:

<Node1>

</Node1>

结果是:

<Node1>
  <Node2>
    <Node3 name="1" value="newValue">
      <Node4>
        <Node5 />
      </Node4>
    </Node3>
  </Node2>
</Node1>

在此输入上运行时:

<Node1>
  <Node2>
    <Node3 name="2" value="value3" />
  </Node2>
</Node1>

结果是:

<Node1>
  <Node2>
    <Node3 name="2" value="value3" />
    <Node3 name="1" value="newValue">
      <Node4>
        <Node5 />
      </Node4>
    </Node3>
  </Node2>
</Node1>

在此输入上运行时:

<Node1>
  <Node2>
    <Node3 name="1" value="value1" otherAttribute="7" />
    <Node3 name="2" value="value3" otherAttribute="9"  />
  </Node2>
</Node1>

结果是:

<Node1>
  <Node2>
    <Node3 name="1" value="newValue" otherAttribute="7">
      <Node4>
        <Node5 />
      </Node4>
    </Node3>
    <Node3 name="2" value="value3" otherAttribute="9" />
  </Node2>
</Node1>
于 2013-03-29T19:21:21.313 回答
1

这是一个较短的解决方案

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

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

 <xsl:template match="Node1[not(Node2)]">
  <Node1>
   <xsl:apply-templates select="@*|node()"/>
      <Node2>
        <Node3 name="1" value="newValue" />
      </Node2>
  </Node1>
 </xsl:template>

 <xsl:template match="Node3[@name='1']">
  <Node3 value="newValue">
   <xsl:apply-templates select="@*[not(name()='value')]|node()"/>
  </Node3>
 </xsl:template>

 <xsl:template match="Node2[not(Node3[@name='1'])]">
  <Node2>
   <xsl:apply-templates select="@*| node()"/>
    <Node3 name="1" value="newValue" />
  </Node2>
 </xsl:template>
</xsl:stylesheet>

在此 XML 文档上运行时:

<Node1>

</Node1>

结果是

<Node1>
  <Node2>
    <Node3 name="1" value="newValue" />
  </Node2>
</Node1>

在此 XML 文档上运行时:

<Node1>
  <Node2>
    <Node3 name="2" value="value3" />
  </Node2>
</Node1>

结果是

<Node1>
  <Node2>
    <Node3 name="2" value="value3" />
    <Node3 name="1" value="newValue" />
  </Node2>"
</Node1>

在此 XML 文档上运行时

<Node1>
  <Node2>
    <Node3 name="1" value="value1" />
    <Node3 name="2" value="value3" />
  </Node2>
</Node1>

结果是

<Node1>
  <Node2>
    <Node3 name="1" value="newValue" />
    <Node3 name="2" value="value3" />
  </Node2>
</Node1>

最后,在此 XML 文档上运行时:

<Node1>
  <Node2>
    <Node3 name="1" value="value1" otherAttribute="7" />
    <Node3 name="2" value="value3" otherAttribute="9"  />
  </Node2>
</Node1>

结果是

<Node1>
   <Node2>
      <Node3 value="newValue" name="1" otherAttribute="7"/>
      <Node3 name="2" value="value3" otherAttribute="9"/>
   </Node2>
</Node1>
于 2013-03-30T04:14:13.777 回答