xmlutil.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /*
  2. * @copyright
  3. * Copyright © Microsoft Open Technologies, Inc.
  4. *
  5. * All Rights Reserved
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http: *www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
  14. * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
  15. * ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A
  16. * PARTICULAR PURPOSE, MERCHANTABILITY OR NON-INFRINGEMENT.
  17. *
  18. * See the Apache License, Version 2.0 for the specific language
  19. * governing permissions and limitations under the License.
  20. */
  21. 'use strict';
  22. var _ = require('underscore');
  23. var select = require('xpath.js');
  24. var XMLSerializer = require('xmldom').XMLSerializer;
  25. var constants = require('./constants');
  26. /**
  27. * @namespace XmlUtil
  28. * @private
  29. */
  30. var XPATH_PATH_TEMPLATE = '*[local-name() = \'LOCAL_NAME\' and namespace-uri() = \'NAMESPACE\']';
  31. /**
  32. * The xpath implementation being used does not have a way of matching expanded namespace.
  33. * This method takes an xpath query and expands all of the namespaces involved. It then
  34. * re-writes the query in to a longer form that directory matches the correct namespaces.
  35. * @private
  36. * @static
  37. * @memberOf XmlUtil
  38. * @param {string} xpath The expath query string to expand.
  39. * @returns {string} An expanded xpath query.
  40. */
  41. function expandQNames(xpath) {
  42. var namespaces = constants.XmlNamespaces;
  43. var pathParts = xpath.split('/');
  44. for (var i=0; i < pathParts.length; i++) {
  45. if (pathParts[i].indexOf(':') !== -1) {
  46. var QNameParts = pathParts[i].split(':');
  47. if (QNameParts.length !== 2) {
  48. throw new Error('Unable to parse XPath string : ' + xpath + ' : with QName : ' + pathParts[i]);
  49. }
  50. var expandedPath = XPATH_PATH_TEMPLATE.replace('LOCAL_NAME', QNameParts[1]);
  51. expandedPath = expandedPath.replace('NAMESPACE', namespaces[QNameParts[0]]);
  52. pathParts[i] = expandedPath;
  53. }
  54. }
  55. return pathParts.join('/');
  56. }
  57. var exports = {
  58. /**
  59. * Performs an xpath select that does appropriate namespace matching since the imported
  60. * xpath module does not properly handle namespaces.
  61. * @static
  62. * @memberOf XmlUtil
  63. * @param {object} dom A dom object created by the xmldom module
  64. * @param {string} xpath An xpath expression
  65. * @return {array} An array of matching dom nodes.
  66. */
  67. xpathSelect : function (dom, xpath) {
  68. return select(dom, expandQNames(xpath));
  69. },
  70. /**
  71. * Given a dom node serializes all immediate children that are xml elements.
  72. * @static
  73. * @memberOf XmlUtil
  74. * @param {object} node An xml dom node.
  75. * @return {string} Serialized xml.
  76. */
  77. serializeNodeChildren : function(node) {
  78. var doc = '';
  79. var sibling = node.firstChild;
  80. var serializer = new XMLSerializer();
  81. while (sibling) {
  82. if (this.isElementNode(sibling)) {
  83. doc += serializer.serializeToString(sibling);
  84. }
  85. sibling = sibling.nextSibling;
  86. }
  87. return doc !== '' ? doc : null;
  88. },
  89. /**
  90. * Detects whether the passed in dom node represents an xml element.
  91. * @static
  92. * @memberOf XmlUtil
  93. * @param {object} node An xml dom node.
  94. * @return {Boolean} true if the node represents an element.
  95. */
  96. isElementNode : function(node) {
  97. return _.has(node, 'tagName');
  98. },
  99. /**
  100. * Given an xmldom node this function returns any text data contained within.
  101. * @static
  102. * @memberOf XmlUtil
  103. * @param {object} node An xmldom node from which the data should be extracted.
  104. * @return {string} Any data found within the element or null if none is found.
  105. */
  106. findElementText : function(node) {
  107. var sibling = node.firstChild;
  108. while (sibling && !sibling.data) {
  109. sibling = sibling.nextSibling;
  110. }
  111. return sibling.data ? sibling.data : null;
  112. }
  113. };
  114. module.exports = exports;