2

I am working on a project which modifies xml documents. I want to modify either a node value or an attribute value. I was able to do that if I specify that it's a node or an attribute value that I want to modify. Modifying node value in xsl:

<xsl:template match="XPath/text()">newValue</xsl:template>

Modifying attribute value in xsl:

<xsl:template match="XPath">
  <xsl:attribute name="attributeName">newValue</xsl:attribute>
</xsl:template>

But I want to modify the values without specifying that it is a node or an attribute. For example here is a short xml:

<example>
  <test>
    <node attrName="oldAttrValue">
      oldNodeValue
    </node>
  </test>
</example>

I would like to modify the "attrName" attribute value or the "node" node value without specifying which. Is this somehow possible, maybe from an XPath?

Thank you.

1
  • If you don't say which node you want to be modified, how is the system to know? Commented Jul 2, 2015 at 7:56

2 Answers 2

1

I would like to modify the "attrName" attribute value or the "node" node value without specifying which. Is this somehow possible

If I understand your question correctly (which is not at all certain) the answer is no.

Keep in mind that the text contained in an element is a node of its own1, and as such can be selected by an XPath expression or matched by a template's match pattern. An attribute is a node, too - but the value of an attribute is not - and therefore it cannot be selected or matched on its own.

See also: http://www.w3.org/TR/xpath/#data-model

--
(1) More precisely: each span of text contained by an element is a separately addressable node.

Sign up to request clarification or add additional context in comments.

Comments

1

Have a look at Identity Transform templates. Basically, they iterate over and copy every element in your xml (elements and attributes alike). Use this, and then either use template match="..." or if conditional blocks to modify your xml as required. For example:

Source XML

<example>
  <test>
    <node attrName="oldAttrValue">oldNodeValue</node>
    <node attrName="dontModify1">dontModify2</node>
  </test>
</example>

XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <!-- identity transform -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  <!-- modify specific text() nodes -->
  <xsl:template match="text()[.='oldNodeValue']">
    <xsl:text>newElementValue</xsl:text>
  </xsl:template>
  <!-- modify specific attribute nodes -->
  <xsl:template match="@*[.='oldAttrValue']">
    <xsl:attribute name="{name()}">newAttributeValue</xsl:attribute>
  </xsl:template>
</xsl:stylesheet>

Output XML

<example>
  <test>
    <node attrname="newAttributeValue">newElementValue</node>
    <node attrname="dontModify1">dontModify2</node>
  </test>
</example>

If you don't want to specify which attribute/element values to match (i.e. you want to apply the transformation to ALL attribute/element values with non-blank values), simpy replace the text()[.='oldNodeValue'] and @*[.='oldAttrValue'] matches with text()[normalize-space(.)!=''] and @*[normalize-space(.)!=''] respectively.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.