Unable to copy and modify attribute in XSLT when u

2019-03-02 16:06发布

问题:

I'm trying to transform an XML document and modify the attributes of single element but the transform is not getting applied if the root element has a namespace attribute. Simply removing xmlns works fine with my code.

My XML:

<?xml version="1.0"?>
<BIDomain xmlns="http://www.oracle.com/biee/bi-domain">
  <BIInstance name="coreapplication">
    <SecurityOptions sslManualConfig="false" sslEnabled="false" ssoProvider="Custom" ssoEnabled="false">
      <SecurityService>
        <EndpointURI>bisecurity/service</EndpointURI>
      </SecurityService>
    </SecurityOptions>
  </BIInstance>
</BIDomain>

The XSL used:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" version="1.0" standalone="yes" />

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

  <!-- Add the new attributes -->
  <xsl:template match="SecurityOptions">
    <xsl:copy>
            <xsl:attribute name="ssoProviderLogoffURL"/>
            <xsl:attribute name="ssoProviderLogonURL"/>
            <xsl:attribute name="sslVerifyPeers">
                <xsl:value-of select="'false'" />
            </xsl:attribute>           
            <xsl:apply-templates  select="node() | @*"/>
        </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

The end result is the same XML. If I remove the namespace definition from the root element <BIDomain xmlns="http://www.oracle.com/biee/bi-domain"> the transform gets applied normally. I'm assuming that I'm doing something wrong and the namespace attribute is interfering with the matching.

Any ideas?

回答1:

The element you're trying to match is in a namespace (the default namespace), so you need to properly use namespaces in your XSLT:

<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:bi="http://www.oracle.com/biee/bi-domain">
                  <!--   ^----- here   -->
  <xsl:output method="xml" version="1.0" standalone="yes" />

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

  <!-- Add the new attributes -->
                <!--   v------- and here   -->
  <xsl:template match="bi:SecurityOptions">
    <xsl:copy>
      <xsl:attribute name="ssoProviderLogoffURL"/>
      <xsl:attribute name="ssoProviderLogonURL"/>
      <xsl:attribute name="sslVerifyPeers">
        <xsl:value-of select="'false'" />
      </xsl:attribute>           
      <xsl:apply-templates  select="node() | @*"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>


回答2:

xmlns works such that all nodes inherit the xmlns attribute(s) from their parent. What that means is, unless otherwise specified, when your document root contains xmlns="http://www.oracle.com/biee/bi-domain" it applies that namespace to all of the sub tree.

So you're actually looking for a SecurityOptions tag with a namespace of "http://www.oracle.com/biee/bi-domain".

This means that your XSLT will actually need to have something like this:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tmp="http://www.oracle.com/biee/bi-domain">

at the top and the template match would look like this:

<xsl:template match="tmp:SecurityOptions">

Note the tmp: matches the xmlns:tmp; this is called a namespace prefix and allows xml to match the small string of tmp to the large string of "http://www.oracle.com/biee/bi-domain".



标签: xml xslt xpath