1

So our data has xmlns= in a child/parent that is stopping the child's value from being updated by the XSLT

Sample Data (Please note I intentionally removed the xmlns="http://example.com/abc-artifact" from the second record, after <Letter to illustrate that it is what is causing the error):

<Documents>
    <Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <PersonalData>
            <Name>JACK</Name>
        </PersonalData>
        <DocumentXml>
            <Letter xmlns="http://example.com/abc-artifact" xsi:schemaLocation="http://example.com/abc-artifact.xsd" xsi:type="LetterType">
                <HeaderRecord>
                    <DateOfBirth>1971-11-07</DateOfBirth>
                </HeaderRecord>
            </Letter>
        </DocumentXml>
    </Document>
    <Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <PersonalData>
            <Name>TONJA</Name>
        </PersonalData>
        <DocumentXml>
            <Letter xsi:schemaLocation="http://example.com/abc-artifact.xsd" xsi:type="LetterType">
                <HeaderRecord>
                    <DateOfBirth>1974-22-10</DateOfBirth>
                </HeaderRecord>
            </Letter>
        </DocumentXml>
    </Document>
</Documents>

XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:template match="node()">
        <xsl:copy>
            <xsl:apply-templates select="node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="DateOfBirth">
        <xsl:copy>
            <xsl:text>NewDOB</xsl:text>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Output

<Documents>
    <Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <PersonalData>
            <Name>JACK</Name>
        </PersonalData>
        <DocumentXml>
            <Letter xmlns="http://example.com/abc-artifact">
                <HeaderRecord>
                    <DateOfBirth>1971-11-07</DateOfBirth>
                </HeaderRecord>
            </Letter>
        </DocumentXml>
    </Document>
    <Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <PersonalData>
            <Name>TONJA</Name>
        </PersonalData>
        <DocumentXml>
            <Letter>
                <HeaderRecord>
                    <DateOfBirth>NewDOB</DateOfBirth>
                </HeaderRecord>
            </Letter>
        </DocumentXml>
    </Document>
</Documents>

So you can see the <DateOfBirth> updated for the second record, but not the first. Our team does not control the data and cannot ask them to remove the xmlns="http://example.com/abc-artifact". Any suggestions? Thanks

John Minze
  • 127
  • 12
  • [XSLT with XML source that has a default namespace set to xmlns](http://stackoverflow.com/questions/1344158/xslt-with-xml-source-that-has-a-default-namespace-set-to-xmlns) – har07 Jan 07 '16 at 16:14

3 Answers3

2

When you have a default namespace (unprefixed namespace) like that in your input, you can bind that namespace uri to a prefix in your XSLT so that it will match correctly.

Also, the xsl:copy will handle the namespace for you.

Example...

XML Input (added the namespace back to the second Letter)

<Documents>
    <Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <PersonalData>
            <Name>JACK</Name>
        </PersonalData>
        <DocumentXml>
            <Letter xmlns="http://example.com/abc-artifact" xsi:schemaLocation="http://example.com/abc-artifact.xsd" xsi:type="LetterType">
                <HeaderRecord>
                    <DateOfBirth>1971-11-07</DateOfBirth>
                </HeaderRecord>
            </Letter>
        </DocumentXml>
    </Document>
    <Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <PersonalData>
            <Name>TONJA</Name>
        </PersonalData>
        <DocumentXml>
            <Letter xmlns="http://example.com/abc-artifact" xsi:schemaLocation="http://example.com/abc-artifact.xsd" xsi:type="LetterType">
                <HeaderRecord>
                    <DateOfBirth>1974-22-10</DateOfBirth>
                </HeaderRecord>
            </Letter>
        </DocumentXml>
    </Document>
</Documents>

XSLT 1.0

<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:abc="http://example.com/abc-artifact">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

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

  <xsl:template match="abc:DateOfBirth">
    <xsl:copy>
      <xsl:text>NewDOB</xsl:text>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

XML Output

<Documents>
   <Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <PersonalData>
         <Name>JACK</Name>
      </PersonalData>
      <DocumentXml>
         <Letter xmlns="http://example.com/abc-artifact" xsi:schemaLocation="http://example.com/abc-artifact.xsd" xsi:type="LetterType">
            <HeaderRecord>
               <DateOfBirth>NewDOB</DateOfBirth>
            </HeaderRecord>
         </Letter>
      </DocumentXml>
   </Document>
   <Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <PersonalData>
         <Name>TONJA</Name>
      </PersonalData>
      <DocumentXml>
         <Letter xmlns="http://example.com/abc-artifact" xsi:schemaLocation="http://example.com/abc-artifact.xsd" xsi:type="LetterType">
            <HeaderRecord>
               <DateOfBirth>NewDOB</DateOfBirth>
            </HeaderRecord>
         </Letter>
      </DocumentXml>
   </Document>
</Documents>

Also, if you're just changing the text you could match it specifically and let the identity transform handle the element/attribute(s)...

<xsl:template match="abc:DateOfBirth/text()">
    <xsl:text>NewDOB</xsl:text>>
</xsl:template>
Daniel Haley
  • 51,389
  • 6
  • 69
  • 95
1

I understand that the issue you are facing is due to namespaces.

You can add the namespace that was removed in the xml.

Here is the xslt that is modified in order to your requirement.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="//*[local-name()='DateOfBirth']">
        <xsl:element name="DateOfBirth" namespace="http://example.com/abc-artifact">
            <xsl:text>NewDOB</xsl:text>
      </xsl:element>
    </xsl:template>
</xsl:stylesheet>

And you would see the below output xml

<?xml version="1.0" encoding="UTF-8"?>
<Documents>
   <Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <PersonalData>
         <Name>JACK</Name>
      </PersonalData>
      <DocumentXml>
         <Letter xmlns="http://example.com/abc-artifact" xsi:schemaLocation="http://example.com/abc-artifact.xsd" xsi:type="LetterType">
            <HeaderRecord>
               <DateOfBirth>NewDOB</DateOfBirth>
            </HeaderRecord>
         </Letter>
      </DocumentXml>
   </Document>
   <Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <PersonalData>
         <Name>TONJA</Name>
      </PersonalData>
      <DocumentXml>
         <Letter xmlns="http://example.com/abc-artifact" xsi:schemaLocation="http://example.com/abc-artifact.xsd" xsi:type="LetterType">
            <HeaderRecord>
               <DateOfBirth>NewDOB</DateOfBirth>
            </HeaderRecord>
         </Letter>
      </DocumentXml>
   </Document>
</Documents>

Hoping that it was you were trying to address and now see the intended output.

EDIT: You can see the changes in the 2nd template which deals with namespace

Rao
  • 20,781
  • 11
  • 57
  • 77
  • Namespaces are presumed to be there for a reason. Ignoring a namespace by using only the local name is not good practice. – michael.hor257k Jan 07 '16 at 17:08
  • @michael.hor257k, agree for the first part. It is using default namespace for the element `DateOfBirth` as user is requested. Are you talking about the same? – Rao Jan 07 '16 at 17:14
  • 1
    I am talking about this part ``. The other part, ``, could be handled simply by ``. – michael.hor257k Jan 07 '16 at 17:22
1

Your template:

<xsl:template match="DateOfBirth">

does not match DateOfBirth elements that are in a namespace. For this, you must use a fully-qualified name of the element. First, declare the namespace and bind it to a prefix, then use that prefix when addressing the element:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:abc="http://example.com/abc-artifact" >
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

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

<xsl:template match="abc:DateOfBirth">
    <xsl:copy>
        <xsl:text>NewDOB</xsl:text>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>
michael.hor257k
  • 113,275
  • 6
  • 33
  • 51
  • It is losing the attributes of `Letter` element. – Rao Jan 07 '16 at 17:36
  • Right, I meant to say that schemalocation and type. – Rao Jan 07 '16 at 18:18
  • @Rao If OP needs them, he can copy them. It doesn't seem like he wants them, though. – michael.hor257k Jan 07 '16 at 18:26
  • @Rao This worked great Michael! Thanks. I am not sure I understand your comment Rao. I ran the XSLT and ran a compare in XMLSpy and the only items that changed were expected. If there is something I should be worried about please let me know. Thanks – John Minze Jan 07 '16 at 18:30
  • This worked great Michael. You have helped me a few times before. Thanks! – John Minze Jan 07 '16 at 18:31
  • @JohnMinze The question is whether you want to copy all the attributes in your input to the output. This is not really related to your question, and has to do with the fact that your first template is different from the standard *identity transform* template. I assumed that was on purpose and therefore kept it as is. – michael.hor257k Jan 07 '16 at 18:45
  • Sorry, I was just showing what the output was and was focused on the data. I did not state it but I only wanted the to change that one element value. It seems like both your solution and @Roa solution does that, without changing anything else. Why did you state it is not good practice? I am fairly new to this so please excuse my ignorance. – John Minze Jan 07 '16 at 19:32
  • @JohnMinze I am afraid you are mixing two unrelated issues. My comment about good practice was about ignoring namespaces. This has nothing to do with copying (or not) attributes. – michael.hor257k Jan 07 '16 at 19:36