1 // Copyright 2017 PDFium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com 6 7 #include "core/fxcrt/xml/cfx_xmlelement.h" 8 9 #include <utility> 10 11 #include "core/fxcrt/cfx_widetextbuf.h" 12 #include "core/fxcrt/fx_extension.h" 13 #include "core/fxcrt/xml/cfx_xmlchardata.h" 14 #include "core/fxcrt/xml/cfx_xmldocument.h" 15 #include "core/fxcrt/xml/cfx_xmltext.h" 16 CFX_XMLElement(const WideString & wsTag)17CFX_XMLElement::CFX_XMLElement(const WideString& wsTag) : name_(wsTag) { 18 ASSERT(!name_.IsEmpty()); 19 } 20 21 CFX_XMLElement::~CFX_XMLElement() = default; 22 GetType() const23CFX_XMLNode::Type CFX_XMLElement::GetType() const { 24 return Type::kElement; 25 } 26 Clone(CFX_XMLDocument * doc)27CFX_XMLNode* CFX_XMLElement::Clone(CFX_XMLDocument* doc) { 28 auto* node = doc->CreateNode<CFX_XMLElement>(name_); 29 node->attrs_ = attrs_; 30 31 // TODO(dsinclair): This clone is wrong. It doesn't clone all child nodes just 32 // text nodes? 33 for (CFX_XMLNode* pChild = GetFirstChild(); pChild; 34 pChild = pChild->GetNextSibling()) { 35 if (pChild->GetType() == Type::kText) 36 node->AppendLastChild(pChild->Clone(doc)); 37 } 38 return node; 39 } 40 GetLocalTagName() const41WideString CFX_XMLElement::GetLocalTagName() const { 42 auto pos = name_.Find(L':'); 43 return pos.has_value() ? name_.Last(name_.GetLength() - pos.value() - 1) 44 : name_; 45 } 46 GetNamespacePrefix() const47WideString CFX_XMLElement::GetNamespacePrefix() const { 48 auto pos = name_.Find(L':'); 49 return pos.has_value() ? name_.First(pos.value()) : WideString(); 50 } 51 GetNamespaceURI() const52WideString CFX_XMLElement::GetNamespaceURI() const { 53 WideString attr(L"xmlns"); 54 WideString wsPrefix = GetNamespacePrefix(); 55 if (!wsPrefix.IsEmpty()) { 56 attr += L":"; 57 attr += wsPrefix; 58 } 59 const CFX_XMLNode* pNode = this; 60 while (pNode && pNode->GetType() == Type::kElement) { 61 auto* pElement = static_cast<const CFX_XMLElement*>(pNode); 62 if (!pElement->HasAttribute(attr)) { 63 pNode = pNode->GetParent(); 64 continue; 65 } 66 return pElement->GetAttribute(attr); 67 } 68 return WideString(); 69 } 70 GetTextData() const71WideString CFX_XMLElement::GetTextData() const { 72 CFX_WideTextBuf buffer; 73 for (CFX_XMLNode* pChild = GetFirstChild(); pChild; 74 pChild = pChild->GetNextSibling()) { 75 CFX_XMLText* pText = ToXMLText(pChild); 76 if (pText) 77 buffer << pText->GetText(); 78 } 79 return buffer.MakeString(); 80 } 81 Save(const RetainPtr<IFX_SeekableWriteStream> & pXMLStream)82void CFX_XMLElement::Save( 83 const RetainPtr<IFX_SeekableWriteStream>& pXMLStream) { 84 ByteString bsNameEncoded = name_.ToUTF8(); 85 86 pXMLStream->WriteString("<"); 87 pXMLStream->WriteString(bsNameEncoded.AsStringView()); 88 89 for (auto it : attrs_) { 90 // Note, the space between attributes is added by AttributeToString which 91 // writes a blank as the first character. 92 pXMLStream->WriteString( 93 AttributeToString(it.first, it.second).ToUTF8().AsStringView()); 94 } 95 96 if (!GetFirstChild()) { 97 pXMLStream->WriteString(" />\n"); 98 return; 99 } 100 101 pXMLStream->WriteString(">\n"); 102 103 for (CFX_XMLNode* pChild = GetFirstChild(); pChild; 104 pChild = pChild->GetNextSibling()) { 105 pChild->Save(pXMLStream); 106 } 107 pXMLStream->WriteString("</"); 108 pXMLStream->WriteString(bsNameEncoded.AsStringView()); 109 pXMLStream->WriteString(">\n"); 110 } 111 GetFirstChildNamed(WideStringView name) const112CFX_XMLElement* CFX_XMLElement::GetFirstChildNamed(WideStringView name) const { 113 return GetNthChildNamed(name, 0); 114 } 115 GetNthChildNamed(WideStringView name,size_t idx) const116CFX_XMLElement* CFX_XMLElement::GetNthChildNamed(WideStringView name, 117 size_t idx) const { 118 for (auto* child = GetFirstChild(); child; child = child->GetNextSibling()) { 119 CFX_XMLElement* elem = ToXMLElement(child); 120 if (!elem || elem->name_ != name) 121 continue; 122 if (idx == 0) 123 return elem; 124 125 --idx; 126 } 127 return nullptr; 128 } 129 HasAttribute(const WideString & name) const130bool CFX_XMLElement::HasAttribute(const WideString& name) const { 131 return attrs_.find(name) != attrs_.end(); 132 } 133 GetAttribute(const WideString & name) const134WideString CFX_XMLElement::GetAttribute(const WideString& name) const { 135 auto it = attrs_.find(name); 136 return it != attrs_.end() ? it->second : WideString(); 137 } 138 SetAttribute(const WideString & name,const WideString & value)139void CFX_XMLElement::SetAttribute(const WideString& name, 140 const WideString& value) { 141 attrs_[name] = value; 142 } 143 RemoveAttribute(const WideString & name)144void CFX_XMLElement::RemoveAttribute(const WideString& name) { 145 attrs_.erase(name); 146 } 147 AttributeToString(const WideString & name,const WideString & value)148WideString CFX_XMLElement::AttributeToString(const WideString& name, 149 const WideString& value) { 150 WideString ret = L" "; 151 ret += name; 152 ret += L"=\""; 153 ret += EncodeEntities(value); 154 ret += L"\""; 155 return ret; 156 } 157