0

I am trying to use XSL to transform two XML files into HTML. I have everything working, but I have a problem. One of the XML files contains assorted bits of information that I am pulling from. There are no namespace declarations anywhere in the file, but nodes that I need to access are namespace prefixed. My original fix was to add the namespaces to the root node, but I found out I can't do that as the files can't be modified.

If I leave the namespaces off, I get the following in Firefox:

XML Parsing Error: prefix not bound to a namespace

The namespaces should be (but don't exist in the source XML):

xmlns:prop="http://www.blank.com/prop" 
xmlns:item="http://www.blank.com/item" 

How do I solve this?

XML:

<?xml version="1.0" encoding="UTF-8"?>
<collection>
  <prop:id>123</prop:id>
  <document>
    <item:name>Document</item:name>
  </document>
</collection>

XSL: (neither of the value-of elements work)

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html"/>
  <xsl:variable name="propsPath" select="test_Props.xml"/>
  <xsl:variable name="props" select="document($propsPath)" />

  <xsl:template match="/">
    <html><body><div>
      <xsl:value-of select="$props/collection/*[local-name() = 'id']"/>
      <xsl:value-of select="$props/collection/prop:id"/>
    </div></body></html>
  </xsl:template>
</xsl:stylesheet>
James Nix
  • 885
  • 1
  • 6
  • 19
  • 1
    If your input uses prefixes without binding them to a namespace, then it's not a well-formed XML document and cannot be processed by XSLT. – michael.hor257k Jul 31 '17 at 18:06

1 Answers1

1

EDIT: This post does not solve the specific question. Nevertheless I leave it here, because it exemplifies a solution to the general problem.

One solution I found to circumvent the namespace issue without modifying test_Props.xml is using an entity reference in a stub file.

So your test_Props.xml file is this:

<?xml version="1.0" encoding="UTF-8"?>
<collection>
  <prop:id>123</prop:id>
  <document>
    <item:name>Document</item:name>
  </document>
</collection>

Now create a stub file around this content named test_Props_stub.xml:

<?xml version="1.0"?>
<!DOCTYPE doc [
<!ENTITY otherFile SYSTEM "test_Props.xml">
]>
<root xmlns:prop="http://www.blank.com/prop" xmlns:item="http://www.blank.com/item">
&otherFile;
</root>

This solution is inspired by this SO answer.
Then just modify the document's name and its path in your XSLT by adding the new root node and you're done:

<xsl:variable name="propsPath" select="'test_Props_stub.xml'"/>
<xsl:variable name="props" select="document($propsPath)/root" />

The rest can stay unmodifyed.
Now the namespaces from the root node of the stub file are applied to the original XML file and the XPath expressions do match.


BTW you had a minor but nasty bug in the following line:

<xsl:variable name="propsPath" select="test_Props.xml"/>

You forgot the quotes around the filename.

zx485
  • 28,498
  • 28
  • 50
  • 59
  • <!ENTITY otherFile SYSTEM "test_Props.xml"> does not work with Firefox unfortunately. I should have stated that I tried that. I apologize. – James Nix Jul 31 '17 at 18:48